You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mina.apache.org by gn...@apache.org on 2014/11/17 21:12:47 UTC
[1/2] mina-sshd git commit: Fix javadocs errors reported on JDK 8
which cause build to fail
Repository: mina-sshd
Updated Branches:
refs/heads/master 4ad43dd16 -> 4b7a87f1a
Fix javadocs errors reported on JDK 8 which cause build to fail
Project: http://git-wip-us.apache.org/repos/asf/mina-sshd/repo
Commit: http://git-wip-us.apache.org/repos/asf/mina-sshd/commit/b0cce8c0
Tree: http://git-wip-us.apache.org/repos/asf/mina-sshd/tree/b0cce8c0
Diff: http://git-wip-us.apache.org/repos/asf/mina-sshd/diff/b0cce8c0
Branch: refs/heads/master
Commit: b0cce8c01cb5a69774ef57d5cd06bbbe85563a57
Parents: 4ad43dd
Author: Guillaume Nodet <gn...@apache.org>
Authored: Tue Oct 21 15:28:37 2014 +0200
Committer: Guillaume Nodet <gn...@apache.org>
Committed: Tue Oct 21 15:28:37 2014 +0200
----------------------------------------------------------------------
.../java/org/apache/sshd/ClientSession.java | 12 +--
.../main/java/org/apache/sshd/SshClient.java | 16 +--
.../java/org/apache/sshd/common/Closeable.java | 6 +-
.../java/org/apache/sshd/common/Session.java | 4 +-
.../org/apache/sshd/common/TcpipForwarder.java | 4 +-
.../keyprovider/ResourceKeyPairProvider.java | 9 +-
.../sshd/common/session/ConnectionService.java | 2 +-
.../sshd/common/util/DirectoryScanner.java | 100 +++++++++----------
.../apache/sshd/common/util/SelectorUtils.java | 20 ++--
.../sshd/server/ServerFactoryManager.java | 2 +-
.../java/org/apache/sshd/server/UserAuth.java | 4 +-
.../sshd/server/auth/gss/UserAuthGSS.java | 8 +-
.../apache/sshd/server/shell/InvertedShell.java | 4 +-
13 files changed, 93 insertions(+), 98 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/b0cce8c0/sshd-core/src/main/java/org/apache/sshd/ClientSession.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/ClientSession.java b/sshd-core/src/main/java/org/apache/sshd/ClientSession.java
index e9f0ed8..cbcc507 100644
--- a/sshd-core/src/main/java/org/apache/sshd/ClientSession.java
+++ b/sshd-core/src/main/java/org/apache/sshd/ClientSession.java
@@ -77,8 +77,8 @@ public interface ClientSession extends Session {
*
* @return the authentication future
* @throws IOException
- * @see {@link #addPasswordIdentity(String)}
- * @see {@link #addPublicKeyIdentity(java.security.KeyPair)}
+ * @see #addPasswordIdentity(String)
+ * @see #addPublicKeyIdentity(java.security.KeyPair)
*/
AuthFuture auth() throws IOException;
@@ -86,7 +86,7 @@ public interface ClientSession extends Session {
* Authenticate the session with the given username using an ssh agent.
*
* @deprecated Use {@link #auth()} instead
- * @see {@link #auth()}
+ * @see #auth()
*/
@Deprecated
AuthFuture authAgent(String username) throws IOException;
@@ -95,7 +95,7 @@ public interface ClientSession extends Session {
* Authenticate the session with the given username and password.
*
* @deprecated Use {@link #auth()} instead
- * @see {@link #auth()}
+ * @see #auth()
*/
@Deprecated
AuthFuture authPassword(String username, String password) throws IOException;
@@ -104,7 +104,7 @@ public interface ClientSession extends Session {
* Authenticate the session with the given username and password.
*
* @deprecated Use {@link #auth()} instead
- * @see {@link #auth()}
+ * @see #auth()
*/
@Deprecated
AuthFuture authInteractive(String username, String password) throws IOException;
@@ -113,7 +113,7 @@ public interface ClientSession extends Session {
* Authenticate the session with the given username and public key.
*
* @deprecated Use {@link #auth()} instead
- * @see {@link #auth()}
+ * @see #auth()
*/
@Deprecated
AuthFuture authPublicKey(String username, KeyPair key) throws IOException;
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/b0cce8c0/sshd-core/src/main/java/org/apache/sshd/SshClient.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/SshClient.java b/sshd-core/src/main/java/org/apache/sshd/SshClient.java
index 0949574..b9fe07d 100644
--- a/sshd-core/src/main/java/org/apache/sshd/SshClient.java
+++ b/sshd-core/src/main/java/org/apache/sshd/SshClient.java
@@ -93,20 +93,10 @@ import org.bouncycastle.openssl.PasswordFinder;
* SshClient client = SshClient.setUpDefaultClient();
* client.start();
* try {
- * ClientSession session = client.connect(host, port).await().getSession();
+ * ClientSession session = client.connect(login, host, port).await().getSession();
+ * session.addPasswordIdentity(password);
+ * session.auth().verify();
*
- * int ret = ClientSession.WAIT_AUTH;
- * while ((ret & ClientSession.WAIT_AUTH) != 0) {
- * System.out.print("Password:");
- * BufferedReader r = new BufferedReader(new InputStreamReader(System.in));
- * String password = r.readLine();
- * session.authPassword(login, password);
- * ret = session.waitFor(ClientSession.WAIT_AUTH | ClientSession.CLOSED | ClientSession.AUTHED, 0);
- * }
- * if ((ret & ClientSession.CLOSED) != 0) {
- * System.err.println("error");
- * System.exit(-1);
- * }
* ClientChannel channel = session.createChannel("shell");
* channel.setIn(new NoCloseInputStream(System.in));
* channel.setOut(new NoCloseOutputStream(System.out));
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/b0cce8c0/sshd-core/src/main/java/org/apache/sshd/common/Closeable.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/Closeable.java b/sshd-core/src/main/java/org/apache/sshd/common/Closeable.java
index ab98bdf..fa9a21d 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/Closeable.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/Closeable.java
@@ -42,7 +42,9 @@ public interface Closeable {
CloseFuture close(boolean immediately);
/**
- * Returns <code>true<</code> if this object has been closed.
+ * Returns <code>true</code> if this object has been closed.
+ *
+ * @return <code>true</code> if closing
*/
boolean isClosed();
@@ -51,6 +53,8 @@ public interface Closeable {
* has been called.
* Note that this method will return <code>true</code> even if
* this {@link #isClosed()} returns <code>true</code>.
+ *
+ * @return <code>true</code> if closing
*/
boolean isClosing();
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/b0cce8c0/sshd-core/src/main/java/org/apache/sshd/common/Session.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/Session.java b/sshd-core/src/main/java/org/apache/sshd/common/Session.java
index 47ad180..166ac41 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/Session.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/Session.java
@@ -177,7 +177,8 @@ public interface Session extends Closeable {
* and the consumer. To further restrict access the setting or getting it from
* the Session you can add static get and set methods, e.g:
*
- * private static final AttributeKey<MyValue> MY_KEY = new AttributeKey<MyValue>();
+ * <pre>
+ * private static final AttributeKey<MyValue> MY_KEY = new AttributeKey<MyValue>();
*
* public static MyValue getMyValue(Session s) {
* return s.getAttribute(MY_KEY);
@@ -186,6 +187,7 @@ public interface Session extends Closeable {
* private void setMyValue(Session s, MyValue value) {
* s.setAttribute(MY_KEY, value);
* }
+ * </pre>
*
* @param <T> type of value stored in the attribute.
*
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/b0cce8c0/sshd-core/src/main/java/org/apache/sshd/common/TcpipForwarder.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/TcpipForwarder.java b/sshd-core/src/main/java/org/apache/sshd/common/TcpipForwarder.java
index 9388b71..aedbf54 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/TcpipForwarder.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/TcpipForwarder.java
@@ -68,14 +68,14 @@ public interface TcpipForwarder extends Closeable {
* Called when the other side requested a remote port forward.
* @param local
* @return the list of bound local addresses
- * @throws Exception
+ * @throws IOException
*/
SshdSocketAddress localPortForwardingRequested(SshdSocketAddress local) throws IOException;
/**
* Called when the other side cancelled a remote port forward.
* @param local
- * @throws Exception
+ * @throws IOException
*/
void localPortForwardingCancelled(SshdSocketAddress local) throws IOException;
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/b0cce8c0/sshd-core/src/main/java/org/apache/sshd/common/keyprovider/ResourceKeyPairProvider.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/keyprovider/ResourceKeyPairProvider.java b/sshd-core/src/main/java/org/apache/sshd/common/keyprovider/ResourceKeyPairProvider.java
index 0cd5d6c..229b70d 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/keyprovider/ResourceKeyPairProvider.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/keyprovider/ResourceKeyPairProvider.java
@@ -40,11 +40,10 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
- * (from org.apache.sshd.common.keyprovider.FileKeyPairProvider)
- * This host key provider loads private keys from the specified resources.
- * <p/>
- * Note that this class has a direct dependency on BouncyCastle and won't work
- * unless it has been correctly registered as a security provider.
+ * <p>This host key provider loads private keys from the specified resources.</p>
+ *
+ * <p>Note that this class has a direct dependency on BouncyCastle and won't work
+ * unless it has been correctly registered as a security provider.</p>
*
* @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
*/
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/b0cce8c0/sshd-core/src/main/java/org/apache/sshd/common/session/ConnectionService.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/session/ConnectionService.java b/sshd-core/src/main/java/org/apache/sshd/common/session/ConnectionService.java
index 45c6266..244b522 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/session/ConnectionService.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/session/ConnectionService.java
@@ -38,7 +38,7 @@ public interface ConnectionService extends Service {
*
* @param channel the channel to register
* @return the id of this channel
- * @throws Exception
+ * @throws IOException
*/
int registerChannel(Channel channel) throws IOException;
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/b0cce8c0/sshd-core/src/main/java/org/apache/sshd/common/util/DirectoryScanner.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/util/DirectoryScanner.java b/sshd-core/src/main/java/org/apache/sshd/common/util/DirectoryScanner.java
index 6fd6741..e559628 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/util/DirectoryScanner.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/util/DirectoryScanner.java
@@ -24,69 +24,70 @@ import java.util.ArrayList;
import java.util.List;
/**
- * Class for scanning a directory for files/directories which match certain
- * criteria.
- * <p/>
- * These criteria consist of selectors and patterns which have been specified.
+ * <p>Class for scanning a directory for files/directories which match certain
+ * criteria.</p>
+ *
+ * <p>These criteria consist of selectors and patterns which have been specified.
* With the selectors you can select which files you want to have included.
* Files which are not selected are excluded. With patterns you can include
- * or exclude files based on their filename.
- * <p/>
- * The idea is simple. A given directory is recursively scanned for all files
+ * or exclude files based on their filename.</p>
+ *
+ * <p>The idea is simple. A given directory is recursively scanned for all files
* and directories. Each file/directory is matched against a set of selectors,
* including special support for matching against filenames with include and
* and exclude patterns. Only files/directories which match at least one
* pattern of the include pattern list or other file selector, and don't match
* any pattern of the exclude pattern list or fail to match against a required
- * selector will be placed in the list of files/directories found.
- * <p/>
- * When no list of include patterns is supplied, "**" will be used, which
+ * selector will be placed in the list of files/directories found.</p>
+ *
+ * <p>When no list of include patterns is supplied, "**" will be used, which
* means that everything will be matched. When no list of exclude patterns is
* supplied, an empty list is used, such that nothing will be excluded. When
- * no selectors are supplied, none are applied.
- * <p/>
- * The filename pattern matching is done as follows:
+ * no selectors are supplied, none are applied.</p>
+ *
+ * <p>The filename pattern matching is done as follows:
* The name to be matched is split up in path segments. A path segment is the
* name of a directory or file, which is bounded by
* <code>File.separator</code> ('/' under UNIX, '\' under Windows).
* For example, "abc/def/ghi/xyz.java" is split up in the segments "abc",
* "def","ghi" and "xyz.java".
- * The same is done for the pattern against which should be matched.
- * <p/>
- * The segments of the name and the pattern are then matched against each
+ * The same is done for the pattern against which should be matched.</p>
+ *
+ * <p>The segments of the name and the pattern are then matched against each
* other. When '**' is used for a path segment in the pattern, it matches
- * zero or more path segments of the name.
- * <p/>
- * There is a special case regarding the use of <code>File.separator</code>s
+ * zero or more path segments of the name.</p>
+ *
+ * <p>There is a special case regarding the use of <code>File.separator</code>s
* at the beginning of the pattern and the string to match:<br>
* When a pattern starts with a <code>File.separator</code>, the string
* to match must also start with a <code>File.separator</code>.
* When a pattern does not start with a <code>File.separator</code>, the
* string to match may not start with a <code>File.separator</code>.
* When one of these rules is not obeyed, the string will not
- * match.
- * <p/>
- * When a name path segment is matched against a pattern path segment, the
+ * match.</p>
+ *
+ * <p>When a name path segment is matched against a pattern path segment, the
* following special characters can be used:<br>
* '*' matches zero or more characters<br>
- * '?' matches one character.
- * <p/>
- * Examples:
- * <p/>
- * "**\*.class" matches all .class files/dirs in a directory tree.
- * <p/>
- * "test\a??.java" matches all files/dirs which start with an 'a', then two
- * more characters and then ".java", in a directory called test.
- * <p/>
- * "**" matches everything in a directory tree.
- * <p/>
- * "**\test\**\XYZ*" matches all files/dirs which start with "XYZ" and where
- * there is a parent directory called test (e.g. "abc\test\def\ghi\XYZ123").
- * <p/>
- * Case sensitivity may be turned off if necessary. By default, it is
- * turned on.
- * <p/>
- * Example of usage:
+ * '?' matches one character.</p>
+ *
+ * <p>Examples:
+ * <br>
+ * <code>"**\*.class"</code> matches all <code>.class</code> files/dirs in a directory tree.
+ * <br>
+ * <code>"test\a??.java"</code> matches all files/dirs which start with an 'a', then two
+ * more characters and then <code>".java"</code>, in a directory called test.
+ * <br>
+ * <code>"**"</code> matches everything in a directory tree.
+ * <br>
+ * <code>"**\test\**\XYZ*"</code> matches all files/dirs which start with <code>"XYZ"</code> and where
+ * there is a parent directory called test (e.g. <code>"abc\test\def\ghi\XYZ123"</code>).
+ * </p>
+ *
+ * <p>Case sensitivity may be turned off if necessary. By default, it is
+ * turned on.</p>
+ *
+ * <p>Example of usage:</p>
* <pre>
* String[] includes = {"**\\*.class"};
* String[] excludes = {"modules\\*\\**"};
@@ -95,15 +96,15 @@ import java.util.List;
* ds.setBasedir(new File("test"));
* ds.setCaseSensitive(true);
* ds.scan();
- * <p/>
+ *
* System.out.println("FILES:");
* String[] files = ds.getIncludedFiles();
- * for (int i = 0; i < files.length; i++) {
+ * for (int i = 0; i < files.length; i++) {
* System.out.println(files[i]);
* }
* </pre>
- * This will scan a directory called test for .class files, but excludes all
- * files in all proper subdirectories of a directory called "modules"
+ * <p>This will scan a directory called test for .class files, but excludes all
+ * files in all proper subdirectories of a directory called "modules".</p>
*
* @author Arnout J. Kuiper
* <a href="mailto:ajkuiper@wxs.nl">ajkuiper@wxs.nl</a>
@@ -179,11 +180,11 @@ public class DirectoryScanner {
}
/**
- * Sets the list of include patterns to use. All '/' and '\' characters
+ * <p>Sets the list of include patterns to use. All '/' and '\' characters
* are replaced by <code>File.separatorChar</code>, so the separator used
- * need not match <code>File.separatorChar</code>.
- * <p/>
- * When a pattern ends with a '/' or '\', "**" is appended.
+ * need not match <code>File.separatorChar</code>.</p>
+ *
+ * <p>When a pattern ends with a '/' or '\', "**" is appended.</p>
*
* @param includes A list of include patterns.
* May be <code>null</code>, indicating that all files
@@ -245,7 +246,6 @@ public class DirectoryScanner {
* @param vpath The path relative to the base directory (needed to
* prevent problems with an absolute path when using
* dir). Must not be <code>null</code>.
- * @throws IOException
*/
protected void scandir(File dir, String vpath) {
String[] newfiles = dir.list();
@@ -348,7 +348,7 @@ public class DirectoryScanner {
/**
* <p>Replace a String with another String inside a larger String,
* for the first <code>max</code> values of the search String.</p>
- * <p/>
+ *
* <p>A <code>null</code> reference passed to this method is a no-op.</p>
*
* @param text text to search and replace in
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/b0cce8c0/sshd-core/src/main/java/org/apache/sshd/common/util/SelectorUtils.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/util/SelectorUtils.java b/sshd-core/src/main/java/org/apache/sshd/common/util/SelectorUtils.java
index 192afaf..6f446b1 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/util/SelectorUtils.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/util/SelectorUtils.java
@@ -56,12 +56,12 @@ public final class SelectorUtils {
}
/**
- * Tests whether or not a given path matches the start of a given
- * pattern up to the first "**".
- * <p/>
- * This is not a general purpose test and should only be used if you
+ * <p>Tests whether or not a given path matches the start of a given
+ * pattern up to the first "**".</p>
+ *
+ * <p>This is not a general purpose test and should only be used if you
* can live with false positives. For example, <code>pattern=**\a</code>
- * and <code>str=b</code> will yield <code>true</code>.
+ * and <code>str=b</code> will yield <code>true</code>.</p>
*
* @param pattern The pattern to match against. Must not be
* <code>null</code>.
@@ -75,12 +75,12 @@ public final class SelectorUtils {
}
/**
- * Tests whether or not a given path matches the start of a given
- * pattern up to the first "**".
- * <p/>
- * This is not a general purpose test and should only be used if you
+ * <p>Tests whether or not a given path matches the start of a given
+ * pattern up to the first "**".</p>
+ *
+ * <p>This is not a general purpose test and should only be used if you
* can live with false positives. For example, <code>pattern=**\a</code>
- * and <code>str=b</code> will yield <code>true</code>.
+ * and <code>str=b</code> will yield <code>true</code>.</p>
*
* @param pattern The pattern to match against. Must not be
* <code>null</code>.
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/b0cce8c0/sshd-core/src/main/java/org/apache/sshd/server/ServerFactoryManager.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/ServerFactoryManager.java b/sshd-core/src/main/java/org/apache/sshd/server/ServerFactoryManager.java
index 11e2d93..e7fd556 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/ServerFactoryManager.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/ServerFactoryManager.java
@@ -108,7 +108,7 @@ public interface ServerFactoryManager extends FactoryManager {
public static final String MODULI_URL = "moduli-url";
/**
- * Retrieve the list of named factories for <code>UserAuth<code> objects.
+ * Retrieve the list of named factories for <code>UserAuth</code> objects.
*
* @return a list of named <code>UserAuth</code> factories, never <code>null</code>
*/
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/b0cce8c0/sshd-core/src/main/java/org/apache/sshd/server/UserAuth.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/UserAuth.java b/sshd-core/src/main/java/org/apache/sshd/server/UserAuth.java
index 004151f..c581cbd 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/UserAuth.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/UserAuth.java
@@ -39,7 +39,7 @@ public interface UserAuth {
* @param username the user trying to log in
* @param buffer the request buffer containing parameters specific to this request
* @return <code>true</code> if the authentication succeeded, <code>false</code> if the authentication
- * failed and <code>null</code></code>is not finished yet
+ * failed and <code>null</code> if not finished yet
* @throws Exception if the authentication fails
*/
Boolean auth(ServerSession session, String username, String service, Buffer buffer) throws Exception;
@@ -49,7 +49,7 @@ public interface UserAuth {
*
* @param buffer the request buffer containing parameters specific to this request
* @return <code>true</code> if the authentication succeeded, <code>false</code> if the authentication
- * failed and <code>null</code></code>is not finished yet
+ * failed and <code>null</code> if not finished yet
* @throws Exception if the authentication fails
*/
Boolean next(Buffer buffer) throws Exception;
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/b0cce8c0/sshd-core/src/main/java/org/apache/sshd/server/auth/gss/UserAuthGSS.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/auth/gss/UserAuthGSS.java b/sshd-core/src/main/java/org/apache/sshd/server/auth/gss/UserAuthGSS.java
index 7bcaffe..4b5db95 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/auth/gss/UserAuthGSS.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/auth/gss/UserAuthGSS.java
@@ -33,10 +33,10 @@ import org.ietf.jgss.MessageProp;
import org.ietf.jgss.Oid;
/**
- * Prototype user authentication handling gssapi-with-mic. Implements <code>HandshakingUserAuth</code> because
- * the process involves several steps.
- * <p/>
- * Several methods are available for overriding in specific circumstances.
+ * <p>Prototype user authentication handling gssapi-with-mic. Implements <code>HandshakingUserAuth</code> because
+ * the process involves several steps.</p>
+ *
+ * <p>Several methods are available for overriding in specific circumstances.</p>
*/
public class UserAuthGSS extends AbstractUserAuth {
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/b0cce8c0/sshd-core/src/main/java/org/apache/sshd/server/shell/InvertedShell.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/shell/InvertedShell.java b/sshd-core/src/main/java/org/apache/sshd/server/shell/InvertedShell.java
index a9f971e..30ab6b0 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/shell/InvertedShell.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/shell/InvertedShell.java
@@ -27,7 +27,7 @@ import java.util.Map;
* This shell have inverted streams, such as the one obtained when launching a
* new {@link Process} from java. This interface is meant to be used with
* {@link InvertedShellWrapper} class as an implementation of
- * {@link Factory}.
+ * {@link org.apache.sshd.common.Factory}.
*
* @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
*/
@@ -38,7 +38,7 @@ public interface InvertedShell {
* the ssh server to retrieve and use.
*
* @param env
- * @throws Exception
+ * @throws IOException
*/
void start(Map<String,String> env) throws IOException;
[2/2] mina-sshd git commit: [SSHD-371] Support Socks proxy with ssh
tunnelling on the client side
Posted by gn...@apache.org.
[SSHD-371] Support Socks proxy with ssh tunnelling on the client side
Project: http://git-wip-us.apache.org/repos/asf/mina-sshd/repo
Commit: http://git-wip-us.apache.org/repos/asf/mina-sshd/commit/4b7a87f1
Tree: http://git-wip-us.apache.org/repos/asf/mina-sshd/tree/4b7a87f1
Diff: http://git-wip-us.apache.org/repos/asf/mina-sshd/diff/4b7a87f1
Branch: refs/heads/master
Commit: 4b7a87f1a887c82e1f324856e82d47d89d5f1968
Parents: b0cce8c
Author: Guillaume Nodet <gn...@apache.org>
Authored: Mon Nov 17 21:12:33 2014 +0100
Committer: Guillaume Nodet <gn...@apache.org>
Committed: Mon Nov 17 21:12:33 2014 +0100
----------------------------------------------------------------------
.../java/org/apache/sshd/ClientSession.java | 17 ++
.../main/java/org/apache/sshd/SshClient.java | 63 ++--
.../sshd/client/session/ClientSessionImpl.java | 8 +
.../org/apache/sshd/common/TcpipForwarder.java | 5 +
.../common/forward/DefaultTcpipForwarder.java | 143 ++++++----
.../apache/sshd/common/forward/SocksProxy.java | 286 +++++++++++++++++++
.../test/java/org/apache/sshd/ProxyTest.java | 154 ++++++++++
7 files changed, 598 insertions(+), 78 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/4b7a87f1/sshd-core/src/main/java/org/apache/sshd/ClientSession.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/ClientSession.java b/sshd-core/src/main/java/org/apache/sshd/ClientSession.java
index cbcc507..482719b 100644
--- a/sshd-core/src/main/java/org/apache/sshd/ClientSession.java
+++ b/sshd-core/src/main/java/org/apache/sshd/ClientSession.java
@@ -194,6 +194,23 @@ public interface ClientSession extends Session {
void stopRemotePortForwarding(SshdSocketAddress remote) throws IOException;
/**
+ * Start dynamic local port forwarding using a SOCKS proxy.
+ *
+ * @param local
+ * @return
+ * @throws IOException
+ */
+ SshdSocketAddress startDynamicPortForwarding(SshdSocketAddress local) throws IOException;
+
+ /**
+ * Stop a previously started dynamic port forwarding.
+ *
+ * @param local
+ * @throws IOException
+ */
+ void stopDynamicPortForwarding(SshdSocketAddress local) throws IOException;
+
+ /**
* Wait for a specific state.
*/
int waitFor(int mask, long timeout);
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/4b7a87f1/sshd-core/src/main/java/org/apache/sshd/SshClient.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/SshClient.java b/sshd-core/src/main/java/org/apache/sshd/SshClient.java
index b9fe07d..33b7eeb 100644
--- a/sshd-core/src/main/java/org/apache/sshd/SshClient.java
+++ b/sshd-core/src/main/java/org/apache/sshd/SshClient.java
@@ -62,6 +62,7 @@ import org.apache.sshd.common.Closeable;
import org.apache.sshd.common.Factory;
import org.apache.sshd.common.KeyPairProvider;
import org.apache.sshd.common.NamedFactory;
+import org.apache.sshd.common.SshdSocketAddress;
import org.apache.sshd.common.future.SshFutureListener;
import org.apache.sshd.common.io.DefaultIoServiceFactoryFactory;
import org.apache.sshd.common.io.IoConnectFuture;
@@ -362,6 +363,7 @@ public class SshClient extends AbstractFactoryManager implements ClientFactoryMa
boolean agentForward = false;
List<String> command = null;
int logLevel = 0;
+ int socksPort = -1;
boolean error = false;
List<String> identities = new ArrayList<String>();
@@ -373,6 +375,13 @@ public class SshClient extends AbstractFactoryManager implements ClientFactoryMa
break;
}
port = Integer.parseInt(args[++i]);
+ } else if (command == null && "-D".equals(args[i])) {
+ if (i + 1 >= args.length) {
+ System.err.println("option requires an argument: " + args[i]);
+ error = true;
+ break;
+ }
+ socksPort = Integer.parseInt(args[++i]);
} else if (command == null && "-l".equals(args[i])) {
if (i + 1 >= args.length) {
System.err.println("option requires an argument: " + args[i]);
@@ -386,11 +395,11 @@ public class SshClient extends AbstractFactoryManager implements ClientFactoryMa
logLevel += 2;
} else if (command == null && "-vvv".equals(args[i])) {
logLevel += 3;
- } else if ("-A".equals(args[i])) {
+ } else if (command == null && "-A".equals(args[i])) {
agentForward = true;
- } else if ("-a".equals(args[i])) {
+ } else if (command == null && "-a".equals(args[i])) {
agentForward = false;
- } else if ("-i".equals(args[i])) {
+ } else if (command == null && "-i".equals(args[i])) {
if (i + 1 >= args.length) {
System.err.println("option requires and argument: " + args[i]);
error = true;
@@ -402,7 +411,7 @@ public class SshClient extends AbstractFactoryManager implements ClientFactoryMa
error = true;
break;
} else {
- if (host == null) {
+ if (command == null && host == null) {
host = args[i];
} else {
if (command == null) {
@@ -417,7 +426,7 @@ public class SshClient extends AbstractFactoryManager implements ClientFactoryMa
error = true;
}
if (error) {
- System.err.println("usage: ssh [-A|-a] [-v[v][v]] [-l login] [-p port] hostname [command]");
+ System.err.println("usage: ssh [-A|-a] [-v[v][v]] [-D socksPort] [-l login] [-p port] hostname [command]");
System.exit(-1);
}
if (logLevel <= 0) {
@@ -475,6 +484,7 @@ public class SshClient extends AbstractFactoryManager implements ClientFactoryMa
public void welcome(String banner) {
System.out.println(banner);
}
+
public String[] interactive(String destination, String name, String instruction, String[] prompt, boolean[] echo) {
String[] answers = new String[prompt.length];
try {
@@ -507,28 +517,33 @@ public class SshClient extends AbstractFactoryManager implements ClientFactoryMa
ClientSession session = client.connect(login, host, port).await().getSession();
session.auth().verify();
- ClientChannel channel;
- if (command == null) {
- channel = session.createChannel(ClientChannel.CHANNEL_SHELL);
- ((ChannelShell) channel).setAgentForwarding(agentForward);
- channel.setIn(new NoCloseInputStream(System.in));
+ if (socksPort >= 0) {
+ session.startDynamicPortForwarding(new SshdSocketAddress("localhost", socksPort));
+ Thread.sleep(Long.MAX_VALUE);
} else {
- channel = session.createChannel(ClientChannel.CHANNEL_EXEC);
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- Writer w = new OutputStreamWriter(baos);
- for (String cmd : command) {
- w.append(cmd).append(" ");
+ ClientChannel channel;
+ if (command == null) {
+ channel = session.createChannel(ClientChannel.CHANNEL_SHELL);
+ ((ChannelShell) channel).setAgentForwarding(agentForward);
+ channel.setIn(new NoCloseInputStream(System.in));
+ } else {
+ channel = session.createChannel(ClientChannel.CHANNEL_EXEC);
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ Writer w = new OutputStreamWriter(baos);
+ for (String cmd : command) {
+ w.append(cmd).append(" ");
+ }
+ w.append("\n");
+ w.close();
+ channel.setIn(new ByteArrayInputStream(baos.toByteArray()));
}
- w.append("\n");
- w.close();
- channel.setIn(new ByteArrayInputStream(baos.toByteArray()));
+ channel.setOut(new NoCloseOutputStream(System.out));
+ channel.setErr(new NoCloseOutputStream(System.err));
+ channel.open().await();
+ channel.waitFor(ClientChannel.CLOSED, 0);
+ session.close(false);
+ client.stop();
}
- channel.setOut(new NoCloseOutputStream(System.out));
- channel.setErr(new NoCloseOutputStream(System.err));
- channel.open().await();
- channel.waitFor(ClientChannel.CLOSED, 0);
- session.close(false);
- client.stop();
}
}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/4b7a87f1/sshd-core/src/main/java/org/apache/sshd/client/session/ClientSessionImpl.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/session/ClientSessionImpl.java b/sshd-core/src/main/java/org/apache/sshd/client/session/ClientSessionImpl.java
index ea3b53d..e4c0258 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/session/ClientSessionImpl.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/session/ClientSessionImpl.java
@@ -260,6 +260,14 @@ public class ClientSessionImpl extends AbstractSession implements ClientSession
getConnectionService().getTcpipForwarder().stopRemotePortForwarding(remote);
}
+ public SshdSocketAddress startDynamicPortForwarding(SshdSocketAddress local) throws IOException {
+ return getConnectionService().getTcpipForwarder().startDynamicPortForwarding(local);
+ }
+
+ public void stopDynamicPortForwarding(SshdSocketAddress local) throws IOException {
+ getConnectionService().getTcpipForwarder().stopDynamicPortForwarding(local);
+ }
+
protected void handleMessage(Buffer buffer) throws Exception {
synchronized (lock) {
super.handleMessage(buffer);
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/4b7a87f1/sshd-core/src/main/java/org/apache/sshd/common/TcpipForwarder.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/TcpipForwarder.java b/sshd-core/src/main/java/org/apache/sshd/common/TcpipForwarder.java
index aedbf54..cfed8e3 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/TcpipForwarder.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/TcpipForwarder.java
@@ -84,4 +84,9 @@ public interface TcpipForwarder extends Closeable {
*/
@Deprecated
void close();
+
+ SshdSocketAddress startDynamicPortForwarding(SshdSocketAddress local) throws IOException;
+
+ void stopDynamicPortForwarding(SshdSocketAddress local) throws IOException;
+
}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/4b7a87f1/sshd-core/src/main/java/org/apache/sshd/common/forward/DefaultTcpipForwarder.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/forward/DefaultTcpipForwarder.java b/sshd-core/src/main/java/org/apache/sshd/common/forward/DefaultTcpipForwarder.java
index d3256ad..b1b340e 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/forward/DefaultTcpipForwarder.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/forward/DefaultTcpipForwarder.java
@@ -49,12 +49,13 @@ import org.apache.sshd.common.util.Readable;
*
* @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
*/
-public class DefaultTcpipForwarder extends CloseableUtils.AbstractInnerCloseable implements TcpipForwarder, IoHandler {
+public class DefaultTcpipForwarder extends CloseableUtils.AbstractInnerCloseable implements TcpipForwarder {
private final ConnectionService service;
private final Session session;
private final Map<Integer, SshdSocketAddress> localToRemote = new HashMap<Integer, SshdSocketAddress>();
private final Map<Integer, SshdSocketAddress> remoteToLocal = new HashMap<Integer, SshdSocketAddress>();
+ private final Map<Integer, SocksProxy> dynamicLocal = new HashMap<Integer, SocksProxy>();
private final Set<SshdSocketAddress> localForwards = new HashSet<SshdSocketAddress>();
protected IoAcceptor acceptor;
@@ -83,7 +84,7 @@ public class DefaultTcpipForwarder extends CloseableUtils.AbstractInnerCloseable
if (isClosing()) {
throw new IllegalStateException("TcpipForwarder is closing");
}
- SshdSocketAddress bound = doBind(local);
+ SshdSocketAddress bound = doBind(local, new StaticIoHandler());
localToRemote.put(bound.getPort(), remote);
return bound;
}
@@ -124,6 +125,36 @@ public class DefaultTcpipForwarder extends CloseableUtils.AbstractInnerCloseable
}
}
+ public synchronized SshdSocketAddress startDynamicPortForwarding(SshdSocketAddress local) throws IOException {
+ if (local == null) {
+ throw new IllegalArgumentException("Local address is null");
+ }
+ if (local.getPort() < 0) {
+ throw new IllegalArgumentException("Invalid local port: " + local.getPort());
+ }
+ if (isClosed()) {
+ throw new IllegalStateException("TcpipForwarder is closed");
+ }
+ if (isClosing()) {
+ throw new IllegalStateException("TcpipForwarder is closing");
+ }
+ SocksProxy socksProxy = new SocksProxy(service);
+ SshdSocketAddress bound = doBind(local, new SocksProxy(service));
+ dynamicLocal.put(bound.getPort(), socksProxy);
+ return bound;
+ }
+
+ public synchronized void stopDynamicPortForwarding(SshdSocketAddress local) throws IOException {
+ Closeable obj = dynamicLocal.remove(local.getPort());
+ if (obj != null) {
+ obj.close(true);
+ acceptor.unbind(local.toInetSocketAddress());
+ if (acceptor.getBoundAddresses().isEmpty()) {
+ close();
+ }
+ }
+ }
+
public synchronized SshdSocketAddress getForwardedPort(int remotePort) {
return remoteToLocal.get(remotePort);
}
@@ -139,7 +170,7 @@ public class DefaultTcpipForwarder extends CloseableUtils.AbstractInnerCloseable
if (filter == null || !filter.canListen(local, session)) {
throw new IOException("Rejected address: " + local);
}
- SshdSocketAddress bound = doBind(local);
+ SshdSocketAddress bound = doBind(local, new StaticIoHandler());
localForwards.add(bound);
return bound;
}
@@ -160,64 +191,16 @@ public class DefaultTcpipForwarder extends CloseableUtils.AbstractInnerCloseable
@Override
protected synchronized Closeable getInnerCloseable() {
- return builder().close(acceptor).build();
- }
-
- //
- // IoHandler implementation
- //
-
- public void sessionCreated(final IoSession session) throws Exception {
- final TcpipClientChannel channel;
- int localPort = ((InetSocketAddress) session.getLocalAddress()).getPort();
- if (localToRemote.containsKey(localPort)) {
- SshdSocketAddress remote = localToRemote.get(localPort);
- channel = new TcpipClientChannel(TcpipClientChannel.Type.Direct, session, remote);
- } else {
- channel = new TcpipClientChannel(TcpipClientChannel.Type.Forwarded, session, null);
- }
- session.setAttribute(TcpipClientChannel.class, channel);
- this.service.registerChannel(channel);
- channel.open().addListener(new SshFutureListener<OpenFuture>() {
- public void operationComplete(OpenFuture future) {
- Throwable t = future.getException();
- if (t != null) {
- DefaultTcpipForwarder.this.service.unregisterChannel(channel);
- channel.close(false);
- }
- }
- });
- }
-
- public void sessionClosed(IoSession session) throws Exception {
- TcpipClientChannel channel = (TcpipClientChannel) session.getAttribute(TcpipClientChannel.class);
- if (channel != null) {
- log.debug("IoSession {} closed, will now close the channel", session);
- channel.close(false);
- }
- }
-
- public void messageReceived(IoSession session, Readable message) throws Exception {
- TcpipClientChannel channel = (TcpipClientChannel) session.getAttribute(TcpipClientChannel.class);
- Buffer buffer = new Buffer();
- buffer.putBuffer(message);
- channel.waitFor(ClientChannel.OPENED | ClientChannel.CLOSED, Long.MAX_VALUE);
- channel.getInvertedIn().write(buffer.array(), buffer.rpos(), buffer.available());
- channel.getInvertedIn().flush();
- }
-
- public void exceptionCaught(IoSession session, Throwable cause) throws Exception {
- cause.printStackTrace();
- session.close(false);
+ return builder().parallel(dynamicLocal.values()).close(acceptor).build();
}
//
// Private methods
//
- private SshdSocketAddress doBind(SshdSocketAddress address) throws IOException {
+ private SshdSocketAddress doBind(SshdSocketAddress address, IoHandler handler) throws IOException {
if (acceptor == null) {
- acceptor = session.getFactoryManager().getIoServiceFactory().createAcceptor(this);
+ acceptor = session.getFactoryManager().getIoServiceFactory().createAcceptor(handler);
}
Set<SocketAddress> before = acceptor.getBoundAddresses();
try {
@@ -244,4 +227,56 @@ public class DefaultTcpipForwarder extends CloseableUtils.AbstractInnerCloseable
return getClass().getSimpleName() + "[" + session + "]";
}
+ //
+ // Static IoHandler implementation
+ //
+
+ class StaticIoHandler implements IoHandler {
+
+ public void sessionCreated(final IoSession session) throws Exception {
+ final TcpipClientChannel channel;
+ int localPort = ((InetSocketAddress) session.getLocalAddress()).getPort();
+ if (localToRemote.containsKey(localPort)) {
+ SshdSocketAddress remote = localToRemote.get(localPort);
+ channel = new TcpipClientChannel(TcpipClientChannel.Type.Direct, session, remote);
+ } else {
+ channel = new TcpipClientChannel(TcpipClientChannel.Type.Forwarded, session, null);
+ }
+ session.setAttribute(TcpipClientChannel.class, channel);
+ service.registerChannel(channel);
+ channel.open().addListener(new SshFutureListener<OpenFuture>() {
+ public void operationComplete(OpenFuture future) {
+ Throwable t = future.getException();
+ if (t != null) {
+ DefaultTcpipForwarder.this.service.unregisterChannel(channel);
+ channel.close(false);
+ }
+ }
+ });
+ }
+
+ public void sessionClosed(IoSession session) throws Exception {
+ TcpipClientChannel channel = (TcpipClientChannel) session.getAttribute(TcpipClientChannel.class);
+ if (channel != null) {
+ log.debug("IoSession {} closed, will now close the channel", session);
+ channel.close(false);
+ }
+ }
+
+ public void messageReceived(IoSession session, Readable message) throws Exception {
+ TcpipClientChannel channel = (TcpipClientChannel) session.getAttribute(TcpipClientChannel.class);
+ Buffer buffer = new Buffer();
+ buffer.putBuffer(message);
+ channel.waitFor(ClientChannel.OPENED | ClientChannel.CLOSED, Long.MAX_VALUE);
+ channel.getInvertedIn().write(buffer.array(), buffer.rpos(), buffer.available());
+ channel.getInvertedIn().flush();
+ }
+
+ public void exceptionCaught(IoSession session, Throwable cause) throws Exception {
+ cause.printStackTrace();
+ session.close(false);
+ }
+
+ }
+
}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/4b7a87f1/sshd-core/src/main/java/org/apache/sshd/common/forward/SocksProxy.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/forward/SocksProxy.java b/sshd-core/src/main/java/org/apache/sshd/common/forward/SocksProxy.java
new file mode 100644
index 0000000..3f61908
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/common/forward/SocksProxy.java
@@ -0,0 +1,286 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sshd.common.forward;
+
+import java.io.IOException;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.apache.sshd.client.future.OpenFuture;
+import org.apache.sshd.common.SshException;
+import org.apache.sshd.common.SshdSocketAddress;
+import org.apache.sshd.common.future.SshFutureListener;
+import org.apache.sshd.common.io.IoHandler;
+import org.apache.sshd.common.io.IoSession;
+import org.apache.sshd.common.session.ConnectionService;
+import org.apache.sshd.common.util.Buffer;
+import org.apache.sshd.common.util.CloseableUtils;
+
+/**
+ * SOCKS proxy server, supporting simple socks4/5 protocols.
+ *
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class SocksProxy extends CloseableUtils.AbstractCloseable implements IoHandler {
+
+ private final ConnectionService service;
+ private final Map<IoSession, Proxy> proxies = new ConcurrentHashMap<IoSession, Proxy>();
+
+ public SocksProxy(ConnectionService service) {
+ this.service = service;
+ }
+
+ public void sessionCreated(IoSession session) throws Exception {
+ if (isClosing()) {
+ throw new SshException("SocksProxy is closing or closed");
+ }
+ }
+
+ public void sessionClosed(IoSession session) throws Exception {
+ Proxy proxy = proxies.remove(session);
+ if (proxy != null) {
+ proxy.close();
+ }
+ }
+
+ public void messageReceived(final IoSession session, org.apache.sshd.common.util.Readable message) throws Exception {
+ Buffer buffer = new Buffer(message.available());
+ buffer.putBuffer(message);
+ Proxy proxy = proxies.get(session);
+ if (proxy == null) {
+ int version = buffer.getByte();
+ if (version == 0x04) {
+ proxy = new Socks4(session);
+ } else if (version == 0x05) {
+ proxy = new Socks5(session);
+ } else {
+ throw new IllegalStateException("Unsupported version: " + version);
+ }
+ proxy.onMessage(buffer);
+ proxies.put(session, proxy);
+ } else {
+ proxy.onMessage(buffer);
+ }
+ }
+
+ public void exceptionCaught(IoSession ioSession, Throwable cause) throws Exception {
+ log.warn("Exception caught, closing socks proxy", cause);
+ ioSession.close(false);
+ }
+
+ public abstract class Proxy {
+
+ IoSession session;
+ TcpipClientChannel channel;
+
+ protected Proxy(IoSession session) {
+ this.session = session;
+ }
+
+ protected void onMessage(Buffer buffer) throws IOException {
+ channel.getInvertedIn().write(buffer.array(), buffer.rpos(), buffer.available());
+ channel.getInvertedIn().flush();
+ }
+
+ public void close() {
+ if (channel != null) {
+ channel.close(false);
+ }
+ }
+
+ protected int getUByte(Buffer buffer) {
+ return buffer.getByte() & 0xFF;
+ }
+
+ protected int getUShort(Buffer buffer) {
+ return (getUByte(buffer) << 8) + getUByte(buffer);
+ }
+ }
+
+ public class Socks4 extends Proxy {
+ public Socks4(IoSession session) {
+ super(session);
+ }
+
+ @Override
+ protected void onMessage(Buffer buffer) throws IOException {
+ if (channel == null) {
+ int cmd = buffer.getByte();
+ if (cmd != 1) {
+ throw new IllegalStateException("Unsupported socks command: " + cmd);
+ }
+ int port = getUShort(buffer);
+ String host = Integer.toString(getUByte(buffer)) + "."
+ + Integer.toString(getUByte(buffer)) + "."
+ + Integer.toString(getUByte(buffer)) + "."
+ + Integer.toString(getUByte(buffer));
+ String userId = getNTString(buffer);
+ // Socks4a
+ if (host.startsWith("0.0.0.")) {
+ host = getNTString(buffer);
+ }
+ log.debug("Received socks4 connection request to {}:{}", host, port);
+ SshdSocketAddress remote = new SshdSocketAddress(host, port);
+ channel = new TcpipClientChannel(TcpipClientChannel.Type.Direct, session, remote);
+ service.registerChannel(channel);
+ channel.open().addListener(new SshFutureListener<OpenFuture>() {
+ public void operationComplete(OpenFuture future) {
+ onChannelOpened(future);
+ }
+ });
+ } else {
+ super.onMessage(buffer);
+ }
+ }
+
+ protected void onChannelOpened(OpenFuture future) {
+ Buffer buffer = new Buffer(8);
+ buffer.putByte((byte) 0x00);
+ Throwable t = future.getException();
+ if (t != null) {
+ service.unregisterChannel(channel);
+ channel.close(false);
+ buffer.putByte((byte) 0x5b);
+ } else {
+ buffer.putByte((byte) 0x5a);
+ }
+ buffer.putByte((byte) 0x00);
+ buffer.putByte((byte) 0x00);
+ buffer.putByte((byte) 0x00);
+ buffer.putByte((byte) 0x00);
+ buffer.putByte((byte) 0x00);
+ buffer.putByte((byte) 0x00);
+ session.write(buffer);
+ }
+
+ private String getNTString(Buffer buffer) {
+ StringBuilder sb = new StringBuilder();
+ char c;
+ while ((c = (char) getUByte(buffer)) != 0) {
+ sb.append(c);
+ }
+ return sb.toString();
+ }
+
+ }
+
+ public class Socks5 extends Proxy {
+
+ byte[] authMethods;
+ Buffer response;
+
+ public Socks5(IoSession session) {
+ super(session);
+ }
+
+ @Override
+ protected void onMessage(Buffer buffer) throws IOException {
+ if (authMethods == null) {
+ int nbAuthMethods = getUByte(buffer);
+ authMethods = new byte[nbAuthMethods];
+ buffer.getRawBytes(authMethods);
+ boolean foundNoAuth = false;
+ for (int i = 0; i < nbAuthMethods; i++) {
+ foundNoAuth |= authMethods[i] == 0;
+ }
+ buffer = new Buffer(8);
+ buffer.putByte((byte) 0x05);
+ buffer.putByte((byte) (foundNoAuth ? 0x00 : 0xFF));
+ session.write(buffer);
+ if (!foundNoAuth) {
+ throw new IllegalStateException("Received socks5 greeting without NoAuth method");
+ } else {
+ log.debug("Received socks5 greeting");
+ }
+ } else if (channel == null) {
+ response = buffer;
+ int version = getUByte(buffer);
+ if (version != 0x05) {
+ throw new IllegalStateException("Unexpected version: " + version);
+ }
+ int cmd = buffer.getByte();
+ if (cmd != 1) {
+ throw new IllegalStateException("Unsupported socks command: " + cmd);
+ }
+ final int res = buffer.getByte();
+ int type = buffer.getByte();
+ String host;
+ if (type == 0x01) {
+ host = Integer.toString(getUByte(buffer)) + "."
+ + Integer.toString(getUByte(buffer)) + "."
+ + Integer.toString(getUByte(buffer)) + "."
+ + Integer.toString(getUByte(buffer));
+ } else if (type == 0x03) {
+ host = getBLString(buffer);
+ } else if (type == 0x04) {
+ host = Integer.toHexString(getUShort(buffer)) + ":"
+ + Integer.toHexString(getUShort(buffer)) + ":"
+ + Integer.toHexString(getUShort(buffer)) + ":"
+ + Integer.toHexString(getUShort(buffer)) + ":"
+ + Integer.toHexString(getUShort(buffer)) + ":"
+ + Integer.toHexString(getUShort(buffer)) + ":"
+ + Integer.toHexString(getUShort(buffer)) + ":"
+ + Integer.toHexString(getUShort(buffer));
+ } else {
+ throw new IllegalStateException("Unsupported address type: " + type);
+ }
+ int port = getUShort(buffer);
+ log.debug("Received socks5 connection request to {}:{}", host, port);
+ SshdSocketAddress remote = new SshdSocketAddress(host, port);
+ channel = new TcpipClientChannel(TcpipClientChannel.Type.Direct, session, remote);
+ service.registerChannel(channel);
+ channel.open().addListener(new SshFutureListener<OpenFuture>() {
+ public void operationComplete(OpenFuture future) {
+ onChannelOpened(future);
+ }
+ });
+ } else {
+ log.debug("Received socks5 connection message");
+ super.onMessage(buffer);
+ }
+ }
+
+ protected void onChannelOpened(OpenFuture future) {
+ int wpos = response.wpos();
+ response.rpos(0);
+ response.wpos(1);
+ Throwable t = future.getException();
+ if (t != null) {
+ service.unregisterChannel(channel);
+ channel.close(false);
+ response.putByte((byte) 0x01);
+ } else {
+ response.putByte((byte) 0x00);
+ }
+ response.wpos(wpos);
+ session.write(response);
+ }
+
+ private String getBLString(Buffer buffer) {
+ int length = getUByte(buffer);
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < length; i++) {
+ sb.append((char) getUByte(buffer));
+ }
+ return sb.toString();
+ }
+
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/4b7a87f1/sshd-core/src/test/java/org/apache/sshd/ProxyTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/ProxyTest.java b/sshd-core/src/test/java/org/apache/sshd/ProxyTest.java
new file mode 100644
index 0000000..e8170a5
--- /dev/null
+++ b/sshd-core/src/test/java/org/apache/sshd/ProxyTest.java
@@ -0,0 +1,154 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sshd;
+
+import java.io.IOError;
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.net.Proxy;
+import java.net.Socket;
+import java.net.URL;
+import java.net.URLConnection;
+
+import org.apache.mina.core.buffer.IoBuffer;
+import org.apache.mina.core.service.IoAcceptor;
+import org.apache.mina.core.service.IoHandlerAdapter;
+import org.apache.mina.core.session.IoSession;
+import org.apache.mina.transport.socket.nio.NioSocketAcceptor;
+import org.apache.sshd.common.SshdSocketAddress;
+import org.apache.sshd.util.BaseTest;
+import org.apache.sshd.util.BogusForwardingFilter;
+import org.apache.sshd.util.BogusPasswordAuthenticator;
+import org.apache.sshd.util.EchoShellFactory;
+import org.apache.sshd.util.Utils;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.slf4j.LoggerFactory;
+
+import static org.apache.sshd.util.Utils.getFreePort;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+/**
+ * Port forwarding tests
+ */
+public class ProxyTest extends BaseTest {
+
+ private final org.slf4j.Logger log = LoggerFactory.getLogger(getClass());
+
+ private SshServer sshd;
+ private int sshPort;
+ private int echoPort;
+ private IoAcceptor acceptor;
+ private SshClient client;
+
+ @Before
+ public void setUp() throws Exception {
+ sshPort = getFreePort();
+ echoPort = getFreePort();
+
+ sshd = SshServer.setUpDefaultServer();
+ sshd.getProperties().put(SshServer.WINDOW_SIZE, "2048");
+ sshd.getProperties().put(SshServer.MAX_PACKET_SIZE, "256");
+ sshd.setPort(sshPort);
+ sshd.setKeyPairProvider(Utils.createTestHostKeyProvider());
+ sshd.setShellFactory(new EchoShellFactory());
+ sshd.setPasswordAuthenticator(new BogusPasswordAuthenticator());
+ sshd.setTcpipForwardingFilter(new BogusForwardingFilter());
+ sshd.start();
+
+ NioSocketAcceptor acceptor = new NioSocketAcceptor();
+ acceptor.setHandler(new IoHandlerAdapter() {
+ @Override
+ public void messageReceived(IoSession session, Object message) throws Exception {
+ IoBuffer recv = (IoBuffer) message;
+ IoBuffer sent = IoBuffer.allocate(recv.remaining());
+ sent.put(recv);
+ sent.flip();
+ session.write(sent);
+ }
+ });
+ acceptor.setReuseAddress(true);
+ acceptor.bind(new InetSocketAddress(echoPort));
+ this.acceptor = acceptor;
+
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ if (sshd != null) {
+ sshd.stop(true);
+ }
+ if (acceptor != null) {
+ acceptor.dispose(true);
+ }
+ if (client != null) {
+ client.stop();
+ }
+ }
+
+ @Test
+ public void testSocksProxy() throws Exception {
+ ClientSession session = createNativeSession();
+
+ SshdSocketAddress dynamic = session.startDynamicPortForwarding(new SshdSocketAddress("localhost", 0));
+
+ for (int i = 0; i < 10; i++) {
+ Socket s = new Socket(new Proxy(Proxy.Type.SOCKS, new InetSocketAddress("localhost", dynamic.getPort())));
+ s.connect(new InetSocketAddress("localhost", echoPort));
+ s.getOutputStream().write("foo".getBytes());
+ s.getOutputStream().flush();
+ byte[] buf = new byte[1024];
+ int l = s.getInputStream().read(buf);
+ s.close();
+ assertEquals("foo", new String(buf, 0, l));
+ }
+
+ session.stopDynamicPortForwarding(dynamic);
+
+ try {
+ Socket s = new Socket(new Proxy(Proxy.Type.SOCKS, new InetSocketAddress("localhost", dynamic.getPort())));
+ s.connect(new InetSocketAddress("localhost", echoPort));
+ s.getOutputStream().write("foo".getBytes());
+ fail("Expected IOException");
+ } catch (IOException e) {
+ // expected
+ }
+
+ session.close(false).await();
+ }
+
+ protected ClientSession createNativeSession() throws Exception {
+ client = SshClient.setUpDefaultClient();
+ client.getProperties().put(SshServer.WINDOW_SIZE, "2048");
+ client.getProperties().put(SshServer.MAX_PACKET_SIZE, "256");
+ client.setTcpipForwardingFilter(new BogusForwardingFilter());
+ client.start();
+
+ ClientSession session = client.connect("sshd", "localhost", sshPort).await().getSession();
+ session.addPasswordIdentity("sshd");
+ session.auth().verify();
+ return session;
+ }
+
+
+}
+
+