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&lt;MyValue&gt; MY_KEY = new AttributeKey&lt;MyValue&gt;();
      *
      * 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 &lt; 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;
+    }
+
+
+}
+
+