You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mina.apache.org by lg...@apache.org on 2017/08/28 16:34:24 UTC
[1/3] mina-sshd git commit: [SSHD-766] Separate forwarding filter
functionality according to sshd-config options
Repository: mina-sshd
Updated Branches:
refs/heads/master 306bef267 -> aa551bc0e
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/aa551bc0/sshd-core/src/main/java/org/apache/sshd/server/forward/ForwardingFilter.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/forward/ForwardingFilter.java b/sshd-core/src/main/java/org/apache/sshd/server/forward/ForwardingFilter.java
index 6c94581..0f76fef 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/forward/ForwardingFilter.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/forward/ForwardingFilter.java
@@ -18,13 +18,7 @@
*/
package org.apache.sshd.server.forward;
-import java.util.Collections;
-import java.util.EnumSet;
-import java.util.Set;
-
-import org.apache.sshd.common.NamedResource;
import org.apache.sshd.common.session.Session;
-import org.apache.sshd.common.util.GenericUtils;
import org.apache.sshd.common.util.net.SshdSocketAddress;
/**
@@ -32,149 +26,41 @@ import org.apache.sshd.common.util.net.SshdSocketAddress;
*
* @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
*/
-public interface ForwardingFilter {
- /**
- * <p>
- * Determine if the session may arrange for agent forwarding.
- * </p>
- *
- * <p>
- * This server process will open a new listen socket locally and export
- * the address in the {@link org.apache.sshd.agent.SshAgent#SSH_AUTHSOCKET_ENV_NAME} environment
- * variable.
- * </p>
- *
- * @param session The {@link Session} requesting permission to forward the agent.
- * @param requestType The request type string that triggered this call
- * @return true if the agent forwarding is permitted, false if denied.
- */
- boolean canForwardAgent(Session session, String requestType);
-
- /**
- * <p>
- * Determine if the session may arrange for X11 forwarding.
- * </p>
- *
- * <p>
- * This server process will open a new listen socket locally and export
- * the address in the environment so X11 clients can be tunneled to the
- * user's X11 display server.
- * </p>
- *
- * @param session The {@link Session} requesting permission to forward X11 connections.
- * @param requestType The request type string that triggered this call
- * @return true if the X11 forwarding is permitted, false if denied.
- */
- boolean canForwardX11(Session session, String requestType);
-
+public interface ForwardingFilter extends AgentForwardingFilter, X11ForwardingFilter, TcpForwardingFilter {
/**
- * <p>
- * Determine if the session may listen for inbound connections.
- * </p>
- *
- * <p>
- * This server process will open a new listen socket on the address given
- * by the client (usually 127.0.0.1 but may be any address). Any inbound
- * connections to this socket will be tunneled over the session to the
- * client, which the client will then forward the connection to another
- * host on the client's side of the network.
- * </p>
+ * Wraps separate filtering policies into one - any {@code null} one is assumed to be disabled
*
- * @param address address the client has requested this server listen
- * for inbound connections on, and relay them through the client.
- * @param session The {@link Session} requesting permission to listen for connections.
- * @return true if the socket is permitted; false if it must be denied.
+ * @param agentFilter The {@link AgentForwardingFilter}
+ * @param x11Filter The {@link X11ForwardingFilter}
+ * @param tcpFilter The {@link TcpForwardingFilter}
+ * @return The combined implementation
*/
- boolean canListen(SshdSocketAddress address, Session session);
-
- /**
- * The type of requested connection forwarding. The type's {@link #getName()}
- * method returns the SSH request type
- */
- enum Type implements NamedResource {
- Direct("direct-tcpip"),
- Forwarded("forwarded-tcpip");
-
- public static final Set<Type> VALUES =
- Collections.unmodifiableSet(EnumSet.allOf(Type.class));
-
- private final String name;
-
- Type(String name) {
- this.name = name;
- }
-
- @Override
- public final String getName() {
- return name;
+ static ForwardingFilter asForwardingFilter(
+ AgentForwardingFilter agentFilter, X11ForwardingFilter x11Filter, TcpForwardingFilter tcpFilter) {
+ if ((agentFilter == null) && (x11Filter == null) && (tcpFilter == null)) {
+ return RejectAllForwardingFilter.INSTANCE;
}
- /**
- * @param name Either the enum name or the request - ignored if {@code null}/empty
- * @return The matching {@link Type} value - case <U>insensitive</U>,
- * or {@code null} if no match found
- * @see #fromName(String)
- * @see #fromEnumName(String)
- */
- public static Type fromString(String name) {
- if (GenericUtils.isEmpty(name)) {
- return null;
+ return new ForwardingFilter() {
+ @Override
+ public boolean canForwardAgent(Session session, String requestType) {
+ return (agentFilter != null) && agentFilter.canForwardAgent(session, requestType);
}
- Type t = fromName(name);
- if (t == null) {
- t = fromEnumName(name);
+ @Override
+ public boolean canForwardX11(Session session, String requestType) {
+ return (x11Filter != null) && x11Filter.canForwardX11(session, requestType);
}
- return t;
- }
-
- /**
- * @param name The request name - ignored if {@code null}/empty
- * @return The matching {@link Type} value - case <U>insensitive</U>,
- * or {@code null} if no match found
- */
- public static Type fromName(String name) {
- return NamedResource.findByName(name, String.CASE_INSENSITIVE_ORDER, VALUES);
- }
-
- /**
- * @param name The enum value name - ignored if {@code null}/empty
- * @return The matching {@link Type} value - case <U>insensitive</U>,
- * or {@code null} if no match found
- */
- public static Type fromEnumName(String name) {
- if (GenericUtils.isEmpty(name)) {
- return null;
+ @Override
+ public boolean canListen(SshdSocketAddress address, Session session) {
+ return (tcpFilter != null) && tcpFilter.canListen(address, session);
}
- for (Type t : VALUES) {
- if (name.equalsIgnoreCase(t.name())) {
- return t;
- }
+ @Override
+ public boolean canConnect(Type type, SshdSocketAddress address, Session session) {
+ return (tcpFilter != null) && tcpFilter.canConnect(type, address, session);
}
-
- return null;
- }
+ };
}
-
- /**
- * <p>
- * Determine if the session may create an outbound connection.
- * </p>
- *
- * <p>
- * This server process will connect to another server listening on the
- * address specified by the client. Usually this is to another port on
- * the same host (127.0.0.1) but may be to any other system this server
- * can reach on the server's side of the network.
- * </p>
- *
- * @param type The {@link Type} of requested connection forwarding
- * @param address address the client has requested this server listen
- * for inbound connections on, and relay them through the client.
- * @param session session requesting permission to listen for connections.
- * @return true if the socket is permitted; false if it must be denied.
- */
- boolean canConnect(Type type, SshdSocketAddress address, Session session);
}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/aa551bc0/sshd-core/src/main/java/org/apache/sshd/server/forward/TcpForwardingFilter.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/forward/TcpForwardingFilter.java b/sshd-core/src/main/java/org/apache/sshd/server/forward/TcpForwardingFilter.java
new file mode 100644
index 0000000..715190a
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/server/forward/TcpForwardingFilter.java
@@ -0,0 +1,162 @@
+/*
+ * 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.server.forward;
+
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.Set;
+
+import org.apache.sshd.common.NamedResource;
+import org.apache.sshd.common.session.Session;
+import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.common.util.net.SshdSocketAddress;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public interface TcpForwardingFilter {
+ // According to http://www.freebsd.org/cgi/man.cgi?query=sshd_config&sektion=5
+ TcpForwardingFilter DEFAULT = new TcpForwardingFilter() {
+ @Override
+ public boolean canListen(SshdSocketAddress address, Session session) {
+ return true;
+ }
+
+ @Override
+ public boolean canConnect(Type type, SshdSocketAddress address, Session session) {
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ return TcpForwardingFilter.class.getSimpleName() + "[DEFAULT]";
+ }
+ };
+
+ /**
+ * <p>
+ * Determine if the session may listen for inbound connections.
+ * </p>
+ *
+ * <p>
+ * This server process will open a new listen socket on the address given
+ * by the client (usually 127.0.0.1 but may be any address). Any inbound
+ * connections to this socket will be tunneled over the session to the
+ * client, which the client will then forward the connection to another
+ * host on the client's side of the network.
+ * </p>
+ *
+ * @param address address the client has requested this server listen
+ * for inbound connections on, and relay them through the client.
+ * @param session The {@link Session} requesting permission to listen for connections.
+ * @return true if the socket is permitted; false if it must be denied.
+ */
+ boolean canListen(SshdSocketAddress address, Session session);
+
+ /**
+ * The type of requested connection forwarding. The type's {@link #getName()}
+ * method returns the SSH request type
+ */
+ enum Type implements NamedResource {
+ Direct("direct-tcpip"),
+ Forwarded("forwarded-tcpip");
+
+ public static final Set<Type> VALUES =
+ Collections.unmodifiableSet(EnumSet.allOf(Type.class));
+
+ private final String name;
+
+ Type(String name) {
+ this.name = name;
+ }
+
+ @Override
+ public final String getName() {
+ return name;
+ }
+
+ /**
+ * @param name Either the enum name or the request - ignored if {@code null}/empty
+ * @return The matching {@link Type} value - case <U>insensitive</U>,
+ * or {@code null} if no match found
+ * @see #fromName(String)
+ * @see #fromEnumName(String)
+ */
+ public static Type fromString(String name) {
+ if (GenericUtils.isEmpty(name)) {
+ return null;
+ }
+
+ Type t = fromName(name);
+ if (t == null) {
+ t = fromEnumName(name);
+ }
+
+ return t;
+ }
+
+ /**
+ * @param name The request name - ignored if {@code null}/empty
+ * @return The matching {@link Type} value - case <U>insensitive</U>,
+ * or {@code null} if no match found
+ */
+ public static Type fromName(String name) {
+ return NamedResource.findByName(name, String.CASE_INSENSITIVE_ORDER, VALUES);
+ }
+
+ /**
+ * @param name The enum value name - ignored if {@code null}/empty
+ * @return The matching {@link Type} value - case <U>insensitive</U>,
+ * or {@code null} if no match found
+ */
+ public static Type fromEnumName(String name) {
+ if (GenericUtils.isEmpty(name)) {
+ return null;
+ }
+
+ for (Type t : VALUES) {
+ if (name.equalsIgnoreCase(t.name())) {
+ return t;
+ }
+ }
+
+ return null;
+ }
+ }
+
+ /**
+ * <p>
+ * Determine if the session may create an outbound connection.
+ * </p>
+ *
+ * <p>
+ * This server process will connect to another server listening on the
+ * address specified by the client. Usually this is to another port on
+ * the same host (127.0.0.1) but may be to any other system this server
+ * can reach on the server's side of the network.
+ * </p>
+ *
+ * @param type The {@link Type} of requested connection forwarding
+ * @param address address the client has requested this server listen
+ * for inbound connections on, and relay them through the client.
+ * @param session session requesting permission to listen for connections.
+ * @return true if the socket is permitted; false if it must be denied.
+ */
+ boolean canConnect(Type type, SshdSocketAddress address, Session session);
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/aa551bc0/sshd-core/src/main/java/org/apache/sshd/server/forward/TcpipServerChannel.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/forward/TcpipServerChannel.java b/sshd-core/src/main/java/org/apache/sshd/server/forward/TcpipServerChannel.java
index 5ddb601..010fa11 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/forward/TcpipServerChannel.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/forward/TcpipServerChannel.java
@@ -122,7 +122,7 @@ public class TcpipServerChannel extends AbstractServerChannel {
address = new SshdSocketAddress(hostToConnect, portToConnect);
break;
case Forwarded:
- address = service.getTcpipForwarder().getForwardedPort(portToConnect);
+ address = service.getForwardingFilter().getForwardedPort(portToConnect);
break;
default:
throw new IllegalStateException("Unknown server channel type: " + type);
@@ -130,7 +130,7 @@ public class TcpipServerChannel extends AbstractServerChannel {
Session session = getSession();
FactoryManager manager = Objects.requireNonNull(session.getFactoryManager(), "No factory manager");
- ForwardingFilter filter = manager.getTcpipForwardingFilter();
+ TcpForwardingFilter filter = manager.getTcpForwardingFilter();
OpenFuture f = new DefaultOpenFuture(this);
try {
if ((address == null) || (filter == null) || (!filter.canConnect(type, address, session))) {
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/aa551bc0/sshd-core/src/main/java/org/apache/sshd/server/forward/X11ForwardingFilter.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/forward/X11ForwardingFilter.java b/sshd-core/src/main/java/org/apache/sshd/server/forward/X11ForwardingFilter.java
new file mode 100644
index 0000000..b9c6b1a
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/server/forward/X11ForwardingFilter.java
@@ -0,0 +1,51 @@
+/*
+ * 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.server.forward;
+
+import org.apache.sshd.common.session.Session;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+@FunctionalInterface
+public interface X11ForwardingFilter {
+ // According to https://www.freebsd.org/cgi/man.cgi?query=sshd_config&sektion=5
+ X11ForwardingFilter DEFAULT = (session, request) -> false;
+
+ /**
+ * <p>
+ * Determine if the session may arrange for X11 forwarding.
+ * </p>
+ *
+ * <p>
+ * This server process will open a new listen socket locally and export
+ * the address in the environment so X11 clients can be tunneled to the
+ * user's X11 display server.
+ * </p>
+ *
+ * @param session The {@link Session} requesting permission to forward X11 connections.
+ * @param requestType The request type string that triggered this call
+ * @return true if the X11 forwarding is permitted, false if denied.
+ */
+ boolean canForwardX11(Session session, String requestType);
+
+ static X11ForwardingFilter of(boolean enabled) {
+ return (session, request) -> enabled;
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/aa551bc0/sshd-core/src/main/java/org/apache/sshd/server/global/CancelTcpipForwardHandler.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/global/CancelTcpipForwardHandler.java b/sshd-core/src/main/java/org/apache/sshd/server/global/CancelTcpipForwardHandler.java
index 2756174..be42a6e 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/global/CancelTcpipForwardHandler.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/global/CancelTcpipForwardHandler.java
@@ -22,7 +22,7 @@ import java.util.Objects;
import java.util.function.IntUnaryOperator;
import org.apache.sshd.common.SshConstants;
-import org.apache.sshd.common.forward.TcpipForwarder;
+import org.apache.sshd.common.forward.ForwardingFilter;
import org.apache.sshd.common.session.ConnectionService;
import org.apache.sshd.common.session.Session;
import org.apache.sshd.common.session.helpers.AbstractConnectionServiceRequestHandler;
@@ -62,7 +62,7 @@ public class CancelTcpipForwardHandler extends AbstractConnectionServiceRequestH
log.debug("process({})[{}] {} reply={}", connectionService, request, socketAddress, wantReply);
}
- TcpipForwarder forwarder = Objects.requireNonNull(connectionService.getTcpipForwarder(), "No TCP/IP forwarder");
+ ForwardingFilter forwarder = Objects.requireNonNull(connectionService.getForwardingFilter(), "No TCP/IP forwarder");
forwarder.localPortForwardingCancelled(socketAddress);
if (wantReply) {
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/aa551bc0/sshd-core/src/main/java/org/apache/sshd/server/global/TcpipForwardHandler.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/global/TcpipForwardHandler.java b/sshd-core/src/main/java/org/apache/sshd/server/global/TcpipForwardHandler.java
index 7c6ea38..b0ecbf3 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/global/TcpipForwardHandler.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/global/TcpipForwardHandler.java
@@ -22,7 +22,7 @@ import java.util.Objects;
import java.util.function.IntUnaryOperator;
import org.apache.sshd.common.SshConstants;
-import org.apache.sshd.common.forward.TcpipForwarder;
+import org.apache.sshd.common.forward.ForwardingFilter;
import org.apache.sshd.common.session.ConnectionService;
import org.apache.sshd.common.session.Session;
import org.apache.sshd.common.session.helpers.AbstractConnectionServiceRequestHandler;
@@ -59,7 +59,7 @@ public class TcpipForwardHandler extends AbstractConnectionServiceRequestHandler
String address = buffer.getString();
int port = buffer.getInt();
SshdSocketAddress socketAddress = new SshdSocketAddress(address, port);
- TcpipForwarder forwarder = Objects.requireNonNull(connectionService.getTcpipForwarder(), "No TCP/IP forwarder");
+ ForwardingFilter forwarder = Objects.requireNonNull(connectionService.getForwardingFilter(), "No TCP/IP forwarder");
SshdSocketAddress bound = forwarder.localPortForwardingRequested(socketAddress);
if (log.isDebugEnabled()) {
log.debug("process({})[{}][want-reply-{}] {} => {}",
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/aa551bc0/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
index 285b7c1..7a1fa72 100644
--- a/sshd-core/src/test/java/org/apache/sshd/ProxyTest.java
+++ b/sshd-core/src/test/java/org/apache/sshd/ProxyTest.java
@@ -128,7 +128,7 @@ public class ProxyTest extends BaseTestSupport {
sshd = setupTestServer();
PropertyResolverUtils.updateProperty(sshd, FactoryManager.WINDOW_SIZE, 2048);
PropertyResolverUtils.updateProperty(sshd, FactoryManager.MAX_PACKET_SIZE, "256");
- sshd.setTcpipForwardingFilter(AcceptAllForwardingFilter.INSTANCE);
+ sshd.setForwardingFilter(AcceptAllForwardingFilter.INSTANCE);
sshd.addPortForwardingEventListener(serverSideListener);
sshd.start();
sshPort = sshd.getPort();
@@ -288,7 +288,7 @@ public class ProxyTest extends BaseTestSupport {
client = setupTestClient();
PropertyResolverUtils.updateProperty(client, FactoryManager.WINDOW_SIZE, 2048);
PropertyResolverUtils.updateProperty(client, FactoryManager.MAX_PACKET_SIZE, 256);
- client.setTcpipForwardingFilter(AcceptAllForwardingFilter.INSTANCE);
+ client.setForwardingFilter(AcceptAllForwardingFilter.INSTANCE);
if (listener != null) {
client.addPortForwardingEventListener(listener);
}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/aa551bc0/sshd-core/src/test/java/org/apache/sshd/agent/AgentTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/agent/AgentTest.java b/sshd-core/src/test/java/org/apache/sshd/agent/AgentTest.java
index 3442042..eaf3deb 100644
--- a/sshd-core/src/test/java/org/apache/sshd/agent/AgentTest.java
+++ b/sshd-core/src/test/java/org/apache/sshd/agent/AgentTest.java
@@ -115,13 +115,13 @@ public class AgentTest extends BaseTestSupport {
try (SshServer sshd1 = setupTestServer()) {
sshd1.setShellFactory(shellFactory);
sshd1.setAgentFactory(agentFactory);
- sshd1.setTcpipForwardingFilter(AcceptAllForwardingFilter.INSTANCE);
+ sshd1.setForwardingFilter(AcceptAllForwardingFilter.INSTANCE);
sshd1.start();
final int port1 = sshd1.getPort();
try (SshServer sshd2 = setupTestServer()) {
sshd2.setShellFactory(new TestEchoShellFactory());
- sshd1.setTcpipForwardingFilter(AcceptAllForwardingFilter.INSTANCE);
+ sshd1.setForwardingFilter(AcceptAllForwardingFilter.INSTANCE);
sshd2.setAgentFactory(new ProxyAgentFactory());
sshd2.start();
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/aa551bc0/sshd-core/src/test/java/org/apache/sshd/client/ClientAuthenticationManagerTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/client/ClientAuthenticationManagerTest.java b/sshd-core/src/test/java/org/apache/sshd/client/ClientAuthenticationManagerTest.java
index d0cc821..30ce313 100644
--- a/sshd-core/src/test/java/org/apache/sshd/client/ClientAuthenticationManagerTest.java
+++ b/sshd-core/src/test/java/org/apache/sshd/client/ClientAuthenticationManagerTest.java
@@ -39,7 +39,7 @@ import org.apache.sshd.common.Factory;
import org.apache.sshd.common.NamedFactory;
import org.apache.sshd.common.NamedResource;
import org.apache.sshd.common.channel.ChannelListener;
-import org.apache.sshd.common.forward.DefaultTcpipForwarderFactory;
+import org.apache.sshd.common.forward.DefaultForwarderFactory;
import org.apache.sshd.common.forward.PortForwardingEventListener;
import org.apache.sshd.common.io.IoSession;
import org.apache.sshd.common.io.IoWriteFuture;
@@ -236,7 +236,7 @@ public class ClientAuthenticationManagerTest extends BaseTestSupport {
private ClientSession createMockClientSession() throws Exception {
ClientFactoryManager client = Mockito.mock(ClientFactoryManager.class);
- Mockito.when(client.getTcpipForwarderFactory()).thenReturn(DefaultTcpipForwarderFactory.INSTANCE);
+ Mockito.when(client.getForwarderFactory()).thenReturn(DefaultForwarderFactory.INSTANCE);
Mockito.when(client.getSessionListenerProxy()).thenReturn(new SessionListener() {
@Override
public void sessionEvent(Session session, Event event) {
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/aa551bc0/sshd-core/src/test/java/org/apache/sshd/common/forward/ApacheServerApacheClientTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/common/forward/ApacheServerApacheClientTest.java b/sshd-core/src/test/java/org/apache/sshd/common/forward/ApacheServerApacheClientTest.java
index f6ac886..6d5d5c1 100644
--- a/sshd-core/src/test/java/org/apache/sshd/common/forward/ApacheServerApacheClientTest.java
+++ b/sshd-core/src/test/java/org/apache/sshd/common/forward/ApacheServerApacheClientTest.java
@@ -59,7 +59,7 @@ public class ApacheServerApacheClientTest extends AbstractServerCloseTestSupport
LOG.info("Starting SSHD...");
server = SshServer.setUpDefaultServer();
server.setPasswordAuthenticator((u, p, s) -> true);
- server.setTcpipForwardingFilter(AcceptAllForwardingFilter.INSTANCE);
+ server.setForwardingFilter(AcceptAllForwardingFilter.INSTANCE);
server.setKeyPairProvider(new SimpleGeneratorHostKeyProvider());
server.start();
sshServerPort = server.getPort();
@@ -76,7 +76,7 @@ public class ApacheServerApacheClientTest extends AbstractServerCloseTestSupport
@Before
public void createClient() throws IOException {
SshClient client = SshClient.setUpDefaultClient();
- client.setTcpipForwardingFilter(AcceptAllForwardingFilter.INSTANCE);
+ client.setForwardingFilter(AcceptAllForwardingFilter.INSTANCE);
client.start();
LOG.info("Connecting...");
session = client.connect("user", TEST_LOCALHOST, sshServerPort).verify(TIMEOUT).getSession();
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/aa551bc0/sshd-core/src/test/java/org/apache/sshd/common/forward/ApacheServerJSchClientTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/common/forward/ApacheServerJSchClientTest.java b/sshd-core/src/test/java/org/apache/sshd/common/forward/ApacheServerJSchClientTest.java
index 3f15a91..bec67a1 100644
--- a/sshd-core/src/test/java/org/apache/sshd/common/forward/ApacheServerJSchClientTest.java
+++ b/sshd-core/src/test/java/org/apache/sshd/common/forward/ApacheServerJSchClientTest.java
@@ -70,7 +70,7 @@ public class ApacheServerJSchClientTest extends AbstractServerCloseTestSupport {
LOG.info("Starting SSHD...");
server = SshServer.setUpDefaultServer();
server.setPasswordAuthenticator((u, p, s) -> true);
- server.setTcpipForwardingFilter(AcceptAllForwardingFilter.INSTANCE);
+ server.setForwardingFilter(AcceptAllForwardingFilter.INSTANCE);
server.setKeyPairProvider(new SimpleGeneratorHostKeyProvider());
server.start();
sshServerPort = server.getPort();
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/aa551bc0/sshd-core/src/test/java/org/apache/sshd/common/forward/PortForwardingLoadTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/common/forward/PortForwardingLoadTest.java b/sshd-core/src/test/java/org/apache/sshd/common/forward/PortForwardingLoadTest.java
index 0184422..dd076ae 100644
--- a/sshd-core/src/test/java/org/apache/sshd/common/forward/PortForwardingLoadTest.java
+++ b/sshd-core/src/test/java/org/apache/sshd/common/forward/PortForwardingLoadTest.java
@@ -145,7 +145,7 @@ public class PortForwardingLoadTest extends BaseTestSupport {
@Before
public void setUp() throws Exception {
sshd = setupTestServer();
- sshd.setTcpipForwardingFilter(AcceptAllForwardingFilter.INSTANCE);
+ sshd.setForwardingFilter(AcceptAllForwardingFilter.INSTANCE);
sshd.addPortForwardingEventListener(serverSideListener);
sshd.start();
sshPort = sshd.getPort();
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/aa551bc0/sshd-core/src/test/java/org/apache/sshd/common/forward/PortForwardingTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/common/forward/PortForwardingTest.java b/sshd-core/src/test/java/org/apache/sshd/common/forward/PortForwardingTest.java
index 0e23bf9..9b88a84 100644
--- a/sshd-core/src/test/java/org/apache/sshd/common/forward/PortForwardingTest.java
+++ b/sshd-core/src/test/java/org/apache/sshd/common/forward/PortForwardingTest.java
@@ -153,7 +153,7 @@ public class PortForwardingTest extends BaseTestSupport {
sshd = Utils.setupTestServer(PortForwardingTest.class);
PropertyResolverUtils.updateProperty(sshd, FactoryManager.WINDOW_SIZE, 2048);
PropertyResolverUtils.updateProperty(sshd, FactoryManager.MAX_PACKET_SIZE, 256);
- sshd.setTcpipForwardingFilter(AcceptAllForwardingFilter.INSTANCE);
+ sshd.setForwardingFilter(AcceptAllForwardingFilter.INSTANCE);
sshd.addPortForwardingEventListener(SERVER_SIDE_LISTENER);
sshd.start();
sshPort = sshd.getPort();
@@ -162,9 +162,9 @@ public class PortForwardingTest extends BaseTestSupport {
REQUESTS_QUEUE.clear();
}
- TcpipForwarderFactory factory = Objects.requireNonNull(sshd.getTcpipForwarderFactory(), "No TcpipForwarderFactory");
- sshd.setTcpipForwarderFactory(new TcpipForwarderFactory() {
- private final Class<?>[] interfaces = {TcpipForwarder.class};
+ ForwardingFilterFactory factory = Objects.requireNonNull(sshd.getForwarderFactory(), "No ForwarderFactory");
+ sshd.setForwarderFactory(new ForwardingFilterFactory() {
+ private final Class<?>[] interfaces = {ForwardingFilter.class};
private final Map<String, String> method2req =
GenericUtils.<String, String>mapBuilder(String.CASE_INSENSITIVE_ORDER)
.put("localPortForwardingRequested", TcpipForwardHandler.REQUEST)
@@ -172,13 +172,13 @@ public class PortForwardingTest extends BaseTestSupport {
.build();
@Override
- public TcpipForwarder create(ConnectionService service) {
+ public ForwardingFilter create(ConnectionService service) {
Thread thread = Thread.currentThread();
ClassLoader cl = thread.getContextClassLoader();
- TcpipForwarder forwarder = factory.create(service);
- return (TcpipForwarder) Proxy.newProxyInstance(cl, interfaces, new InvocationHandler() {
- private final org.slf4j.Logger log = LoggerFactory.getLogger(TcpipForwarder.class);
+ ForwardingFilter forwarder = factory.create(service);
+ return (ForwardingFilter) Proxy.newProxyInstance(cl, interfaces, new InvocationHandler() {
+ private final org.slf4j.Logger log = LoggerFactory.getLogger(ForwardingFilter.class);
@SuppressWarnings("synthetic-access")
@Override
@@ -797,7 +797,7 @@ public class PortForwardingTest extends BaseTestSupport {
protected ClientSession createNativeSession(PortForwardingEventListener listener) throws Exception {
PropertyResolverUtils.updateProperty(client, FactoryManager.WINDOW_SIZE, 2048);
PropertyResolverUtils.updateProperty(client, FactoryManager.MAX_PACKET_SIZE, 256);
- client.setTcpipForwardingFilter(AcceptAllForwardingFilter.INSTANCE);
+ client.setForwardingFilter(AcceptAllForwardingFilter.INSTANCE);
if (listener != null) {
client.addPortForwardingEventListener(listener);
}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/aa551bc0/sshd-core/src/test/java/org/apache/sshd/server/subsystem/sftp/SshFsMounter.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/server/subsystem/sftp/SshFsMounter.java b/sshd-core/src/test/java/org/apache/sshd/server/subsystem/sftp/SshFsMounter.java
index e67cf23..9320cc7 100644
--- a/sshd-core/src/test/java/org/apache/sshd/server/subsystem/sftp/SshFsMounter.java
+++ b/sshd-core/src/test/java/org/apache/sshd/server/subsystem/sftp/SshFsMounter.java
@@ -317,7 +317,7 @@ public final class SshFsMounter {
sshd.setShellFactory(InteractiveProcessShellFactory.INSTANCE);
sshd.setPasswordAuthenticator(AcceptAllPasswordAuthenticator.INSTANCE);
- sshd.setTcpipForwardingFilter(AcceptAllForwardingFilter.INSTANCE);
+ sshd.setForwardingFilter(AcceptAllForwardingFilter.INSTANCE);
sshd.setCommandFactory(new ScpCommandFactory.Builder().withDelegate(MounterCommandFactory.INSTANCE).build());
sshd.setSubsystemFactories(Collections.singletonList(new SftpSubsystemFactory()));
sshd.start();
[3/3] mina-sshd git commit: [SSHD-766] Separate forwarding filter
functionality according to sshd-config options
Posted by lg...@apache.org.
[SSHD-766] Separate forwarding filter functionality according to sshd-config options
Project: http://git-wip-us.apache.org/repos/asf/mina-sshd/repo
Commit: http://git-wip-us.apache.org/repos/asf/mina-sshd/commit/aa551bc0
Tree: http://git-wip-us.apache.org/repos/asf/mina-sshd/tree/aa551bc0
Diff: http://git-wip-us.apache.org/repos/asf/mina-sshd/diff/aa551bc0
Branch: refs/heads/master
Commit: aa551bc0ed07430ee768e98a57b75cd56f3927e0
Parents: 306bef2
Author: Goldstein Lyor <ly...@c-b4.com>
Authored: Mon Aug 28 15:12:26 2017 +0300
Committer: Lyor Goldstein <ly...@gmail.com>
Committed: Mon Aug 28 19:34:56 2017 +0300
----------------------------------------------------------------------
.../java/org/apache/sshd/client/SshClient.java | 2 +-
.../client/session/AbstractClientSession.java | 24 +-
.../org/apache/sshd/common/BaseBuilder.java | 20 +-
.../org/apache/sshd/common/FactoryManager.java | 25 +-
.../common/config/AllowTcpForwardingValue.java | 63 --
.../sshd/common/config/SshConfigFileReader.java | 13 -
.../common/forward/DefaultForwarderFactory.java | 82 ++
.../common/forward/DefaultForwardingFilter.java | 1003 +++++++++++++++++
.../common/forward/DefaultTcpipForwarder.java | 1007 ------------------
.../forward/DefaultTcpipForwarderFactory.java | 82 --
.../sshd/common/forward/ForwardingFilter.java | 59 +
.../common/forward/ForwardingFilterFactory.java | 37 +
.../sshd/common/forward/TcpipForwarder.java | 54 -
.../common/forward/TcpipForwarderFactory.java | 37 -
.../common/helpers/AbstractFactoryManager.java | 22 +-
.../sshd/common/session/ConnectionService.java | 8 +-
.../helpers/AbstractConnectionService.java | 32 +-
.../java/org/apache/sshd/server/SshServer.java | 56 +-
.../sshd/server/channel/ChannelSession.java | 7 +-
.../server/config/AllowTcpForwardingValue.java | 106 ++
.../config/SshServerConfigFileReader.java | 111 ++
.../server/forward/AgentForwardingFilter.java | 51 +
.../sshd/server/forward/ForwardingFilter.java | 162 +--
.../server/forward/TcpForwardingFilter.java | 162 +++
.../sshd/server/forward/TcpipServerChannel.java | 4 +-
.../server/forward/X11ForwardingFilter.java | 51 +
.../global/CancelTcpipForwardHandler.java | 4 +-
.../sshd/server/global/TcpipForwardHandler.java | 4 +-
.../test/java/org/apache/sshd/ProxyTest.java | 4 +-
.../java/org/apache/sshd/agent/AgentTest.java | 4 +-
.../client/ClientAuthenticationManagerTest.java | 4 +-
.../forward/ApacheServerApacheClientTest.java | 4 +-
.../forward/ApacheServerJSchClientTest.java | 2 +-
.../common/forward/PortForwardingLoadTest.java | 2 +-
.../sshd/common/forward/PortForwardingTest.java | 18 +-
.../server/subsystem/sftp/SshFsMounter.java | 2 +-
36 files changed, 1808 insertions(+), 1520 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/aa551bc0/sshd-core/src/main/java/org/apache/sshd/client/SshClient.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/SshClient.java b/sshd-core/src/main/java/org/apache/sshd/client/SshClient.java
index c8cc1db..e4d37ab 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/SshClient.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/SshClient.java
@@ -378,7 +378,7 @@ public class SshClient extends AbstractFactoryManager implements ClientFactoryMa
protected void checkConfig() {
super.checkConfig();
- Objects.requireNonNull(getTcpipForwarderFactory(), "TcpipForwarderFactory not set");
+ Objects.requireNonNull(getForwarderFactory(), "ForwarderFactory not set");
Objects.requireNonNull(getServerKeyVerifier(), "ServerKeyVerifier not set");
Objects.requireNonNull(getHostConfigEntryResolver(), "HostConfigEntryResolver not set");
Objects.requireNonNull(getClientIdentityLoader(), "ClientIdentityLoader not set");
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/aa551bc0/sshd-core/src/main/java/org/apache/sshd/client/session/AbstractClientSession.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/session/AbstractClientSession.java b/sshd-core/src/main/java/org/apache/sshd/client/session/AbstractClientSession.java
index 9e85843..4e9e6c9 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/session/AbstractClientSession.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/session/AbstractClientSession.java
@@ -58,7 +58,7 @@ import org.apache.sshd.common.channel.Channel;
import org.apache.sshd.common.cipher.BuiltinCiphers;
import org.apache.sshd.common.cipher.CipherNone;
import org.apache.sshd.common.config.keys.KeyUtils;
-import org.apache.sshd.common.forward.TcpipForwarder;
+import org.apache.sshd.common.forward.ForwardingFilter;
import org.apache.sshd.common.future.DefaultKeyExchangeFuture;
import org.apache.sshd.common.future.KeyExchangeFuture;
import org.apache.sshd.common.io.IoSession;
@@ -388,37 +388,43 @@ public abstract class AbstractClientSession extends AbstractSession implements C
@Override
public SshdSocketAddress startLocalPortForwarding(SshdSocketAddress local, SshdSocketAddress remote) throws IOException {
- return getTcpipForwarder().startLocalPortForwarding(local, remote);
+ ForwardingFilter filter = getForwardingFilter();
+ return filter.startLocalPortForwarding(local, remote);
}
@Override
public void stopLocalPortForwarding(SshdSocketAddress local) throws IOException {
- getTcpipForwarder().stopLocalPortForwarding(local);
+ ForwardingFilter filter = getForwardingFilter();
+ filter.stopLocalPortForwarding(local);
}
@Override
public SshdSocketAddress startRemotePortForwarding(SshdSocketAddress remote, SshdSocketAddress local) throws IOException {
- return getTcpipForwarder().startRemotePortForwarding(remote, local);
+ ForwardingFilter filter = getForwardingFilter();
+ return filter.startRemotePortForwarding(remote, local);
}
@Override
public void stopRemotePortForwarding(SshdSocketAddress remote) throws IOException {
- getTcpipForwarder().stopRemotePortForwarding(remote);
+ ForwardingFilter filter = getForwardingFilter();
+ filter.stopRemotePortForwarding(remote);
}
@Override
public SshdSocketAddress startDynamicPortForwarding(SshdSocketAddress local) throws IOException {
- return getTcpipForwarder().startDynamicPortForwarding(local);
+ ForwardingFilter filter = getForwardingFilter();
+ return filter.startDynamicPortForwarding(local);
}
@Override
public void stopDynamicPortForwarding(SshdSocketAddress local) throws IOException {
- getTcpipForwarder().stopDynamicPortForwarding(local);
+ ForwardingFilter filter = getForwardingFilter();
+ filter.stopDynamicPortForwarding(local);
}
- protected TcpipForwarder getTcpipForwarder() {
+ protected ForwardingFilter getForwardingFilter() {
ConnectionService service = Objects.requireNonNull(getConnectionService(), "No connection service");
- return Objects.requireNonNull(service.getTcpipForwarder(), "No forwarder");
+ return Objects.requireNonNull(service.getForwardingFilter(), "No forwarder");
}
@Override
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/aa551bc0/sshd-core/src/main/java/org/apache/sshd/common/BaseBuilder.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/BaseBuilder.java b/sshd-core/src/main/java/org/apache/sshd/common/BaseBuilder.java
index 534ac0e..250dc63 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/BaseBuilder.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/BaseBuilder.java
@@ -30,8 +30,8 @@ import org.apache.sshd.common.cipher.Cipher;
import org.apache.sshd.common.compression.Compression;
import org.apache.sshd.common.file.FileSystemFactory;
import org.apache.sshd.common.file.nativefs.NativeFileSystemFactory;
-import org.apache.sshd.common.forward.DefaultTcpipForwarderFactory;
-import org.apache.sshd.common.forward.TcpipForwarderFactory;
+import org.apache.sshd.common.forward.DefaultForwarderFactory;
+import org.apache.sshd.common.forward.ForwardingFilterFactory;
import org.apache.sshd.common.helpers.AbstractFactoryManager;
import org.apache.sshd.common.kex.BuiltinDHFactories;
import org.apache.sshd.common.kex.KeyExchange;
@@ -59,7 +59,7 @@ public class BaseBuilder<T extends AbstractFactoryManager, S extends BaseBuilder
public static final ForwardingFilter DEFAULT_FORWARDING_FILTER = RejectAllForwardingFilter.INSTANCE;
- public static final TcpipForwarderFactory DEFAULT_FORWARDER_FACTORY = DefaultTcpipForwarderFactory.INSTANCE;
+ public static final ForwardingFilterFactory DEFAULT_FORWARDER_FACTORY = DefaultForwarderFactory.INSTANCE;
/**
* The default {@link BuiltinCiphers} setup in order of preference
@@ -138,7 +138,7 @@ public class BaseBuilder<T extends AbstractFactoryManager, S extends BaseBuilder
protected Factory<Random> randomFactory;
protected List<NamedFactory<Channel>> channelFactories;
protected FileSystemFactory fileSystemFactory;
- protected TcpipForwarderFactory tcpipForwarderFactory;
+ protected ForwardingFilterFactory forwarderFactory;
protected List<RequestHandler<ConnectionService>> globalRequestHandlers;
protected ForwardingFilter forwardingFilter;
@@ -171,8 +171,8 @@ public class BaseBuilder<T extends AbstractFactoryManager, S extends BaseBuilder
forwardingFilter = DEFAULT_FORWARDING_FILTER;
}
- if (tcpipForwarderFactory == null) {
- tcpipForwarderFactory = DEFAULT_FORWARDER_FACTORY;
+ if (forwarderFactory == null) {
+ forwarderFactory = DEFAULT_FORWARDER_FACTORY;
}
return me();
@@ -223,8 +223,8 @@ public class BaseBuilder<T extends AbstractFactoryManager, S extends BaseBuilder
return me();
}
- public S tcpipForwarderFactory(TcpipForwarderFactory tcpipForwarderFactory) {
- this.tcpipForwarderFactory = tcpipForwarderFactory;
+ public S forwarderFactory(ForwardingFilterFactory forwarderFactory) {
+ this.forwarderFactory = forwarderFactory;
return me();
}
@@ -253,8 +253,8 @@ public class BaseBuilder<T extends AbstractFactoryManager, S extends BaseBuilder
ssh.setMacFactories(macFactories);
ssh.setChannelFactories(channelFactories);
ssh.setFileSystemFactory(fileSystemFactory);
- ssh.setTcpipForwardingFilter(forwardingFilter);
- ssh.setTcpipForwarderFactory(tcpipForwarderFactory);
+ ssh.setForwardingFilter(forwardingFilter);
+ ssh.setForwarderFactory(forwarderFactory);
ssh.setGlobalRequestHandlers(globalRequestHandlers);
return ssh;
}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/aa551bc0/sshd-core/src/main/java/org/apache/sshd/common/FactoryManager.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/FactoryManager.java b/sshd-core/src/main/java/org/apache/sshd/common/FactoryManager.java
index 8652cd8..71e06da 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/FactoryManager.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/FactoryManager.java
@@ -27,15 +27,18 @@ import org.apache.sshd.common.channel.Channel;
import org.apache.sshd.common.channel.ChannelListenerManager;
import org.apache.sshd.common.channel.RequestHandler;
import org.apache.sshd.common.file.FileSystemFactory;
+import org.apache.sshd.common.forward.ForwardingFilterFactory;
import org.apache.sshd.common.forward.PortForwardingEventListenerManager;
-import org.apache.sshd.common.forward.TcpipForwarderFactory;
import org.apache.sshd.common.io.IoServiceFactory;
import org.apache.sshd.common.kex.KexFactoryManager;
import org.apache.sshd.common.random.Random;
import org.apache.sshd.common.session.ConnectionService;
import org.apache.sshd.common.session.ReservedSessionMessagesManager;
import org.apache.sshd.common.session.SessionListenerManager;
+import org.apache.sshd.server.forward.AgentForwardingFilter;
import org.apache.sshd.server.forward.ForwardingFilter;
+import org.apache.sshd.server.forward.TcpForwardingFilter;
+import org.apache.sshd.server.forward.X11ForwardingFilter;
/**
* This interface allows retrieving all the <code>NamedFactory</code> used
@@ -415,14 +418,26 @@ public interface FactoryManager
*
* @return The {@link ForwardingFilter} or {@code null}
*/
- ForwardingFilter getTcpipForwardingFilter();
+ ForwardingFilter getForwardingFilter();
+
+ default TcpForwardingFilter getTcpForwardingFilter() {
+ return getForwardingFilter();
+ }
+
+ default AgentForwardingFilter getAgentForwardingFilter() {
+ return getForwardingFilter();
+ }
+
+ default X11ForwardingFilter getX11ForwardingFilter() {
+ return getForwardingFilter();
+ }
/**
- * Retrieve the tcpip forwarder factory used to support tcpip forwarding.
+ * Retrieve the forwarder factory used to support forwarding.
*
- * @return The {@link TcpipForwarderFactory}
+ * @return The {@link ForwardingFilterFactory}
*/
- TcpipForwarderFactory getTcpipForwarderFactory();
+ ForwardingFilterFactory getForwarderFactory();
/**
* Retrieve the <code>FileSystemFactory</code> to be used to traverse the file system.
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/aa551bc0/sshd-core/src/main/java/org/apache/sshd/common/config/AllowTcpForwardingValue.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/config/AllowTcpForwardingValue.java b/sshd-core/src/main/java/org/apache/sshd/common/config/AllowTcpForwardingValue.java
deleted file mode 100644
index c641f33..0000000
--- a/sshd-core/src/main/java/org/apache/sshd/common/config/AllowTcpForwardingValue.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * 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.config;
-
-import java.util.Collections;
-import java.util.EnumSet;
-import java.util.Set;
-
-import org.apache.sshd.common.util.GenericUtils;
-
-/**
- * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
- * @see <A HREF="http://www.freebsd.org/cgi/man.cgi?query=sshd_config&sektion=5">sshd_config(5) section</A>
- */
-public enum AllowTcpForwardingValue {
- ALL,
- NONE,
- LOCAL,
- REMOTE;
-
- public static final Set<AllowTcpForwardingValue> VALUES =
- Collections.unmodifiableSet(EnumSet.allOf(AllowTcpForwardingValue.class));
-
- // NOTE: it also interprets "yes" as "all" and "no" as "none"
- public static AllowTcpForwardingValue fromString(String s) {
- if (GenericUtils.isEmpty(s)) {
- return null;
- }
-
- if ("yes".equalsIgnoreCase(s)) {
- return ALL;
- }
-
- if ("no".equalsIgnoreCase(s)) {
- return NONE;
- }
-
- for (AllowTcpForwardingValue v : VALUES) {
- if (s.equalsIgnoreCase(v.name())) {
- return v;
- }
- }
-
- return null;
- }
-}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/aa551bc0/sshd-core/src/main/java/org/apache/sshd/common/config/SshConfigFileReader.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/config/SshConfigFileReader.java b/sshd-core/src/main/java/org/apache/sshd/common/config/SshConfigFileReader.java
index 7f6b5e8..b6d87d4 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/config/SshConfigFileReader.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/config/SshConfigFileReader.java
@@ -78,21 +78,8 @@ public final class SshConfigFileReader {
public static final char COMMENT_CHAR = '#';
- // Some well known configuration properties names and values
- public static final String BANNER_CONFIG_PROP = "Banner";
- public static final String VISUAL_HOST_KEY = "VisualHostKey";
- public static final String DEFAULT_VISUAL_HOST_KEY = "no";
public static final String COMPRESSION_PROP = "Compression";
public static final String DEFAULT_COMPRESSION = CompressionConfigValue.NO.getName();
- public static final String ALLOW_TCP_FORWARDING_CONFIG_PROP = "AllowTcpForwarding";
- public static final String DEFAULT_TCP_FORWARDING = "yes";
- public static final boolean DEFAULT_TCP_FORWARDING_VALUE = parseBooleanValue(DEFAULT_TCP_FORWARDING);
- public static final String ALLOW_AGENT_FORWARDING_CONFIG_PROP = "AllowAgentForwarding";
- public static final String DEFAULT_AGENT_FORWARDING = "yes";
- public static final boolean DEFAULT_AGENT_FORWARDING_VALUE = parseBooleanValue(DEFAULT_AGENT_FORWARDING);
- public static final String ALLOW_X11_FORWARDING_CONFIG_PROP = "X11Forwarding";
- public static final String DEFAULT_X11_FORWARDING = "yes";
- public static final boolean DEFAULT_X11_FORWARDING_VALUE = parseBooleanValue(DEFAULT_X11_FORWARDING);
public static final String MAX_SESSIONS_CONFIG_PROP = "MaxSessions";
public static final int DEFAULT_MAX_SESSIONS = 10;
public static final String PASSWORD_AUTH_CONFIG_PROP = "PasswordAuthentication";
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/aa551bc0/sshd-core/src/main/java/org/apache/sshd/common/forward/DefaultForwarderFactory.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/forward/DefaultForwarderFactory.java b/sshd-core/src/main/java/org/apache/sshd/common/forward/DefaultForwarderFactory.java
new file mode 100644
index 0000000..ace0562
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/common/forward/DefaultForwarderFactory.java
@@ -0,0 +1,82 @@
+/*
+ * 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.util.Collection;
+import java.util.concurrent.CopyOnWriteArraySet;
+
+import org.apache.sshd.common.session.ConnectionService;
+import org.apache.sshd.common.util.EventListenerUtils;
+
+/**
+ * The default {@link ForwardingFilterFactory} implementation.
+ *
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class DefaultForwarderFactory implements ForwardingFilterFactory, PortForwardingEventListenerManager {
+ public static final DefaultForwarderFactory INSTANCE = new DefaultForwarderFactory() {
+ @Override
+ public void addPortForwardingEventListener(PortForwardingEventListener listener) {
+ throw new UnsupportedOperationException("addPortForwardingListener(" + listener + ") N/A on default instance");
+ }
+
+ @Override
+ public void removePortForwardingEventListener(PortForwardingEventListener listener) {
+ throw new UnsupportedOperationException("removePortForwardingEventListener(" + listener + ") N/A on default instance");
+ }
+
+ @Override
+ public PortForwardingEventListener getPortForwardingEventListenerProxy() {
+ return PortForwardingEventListener.EMPTY;
+ }
+ };
+
+ private final Collection<PortForwardingEventListener> listeners = new CopyOnWriteArraySet<>();
+ private final PortForwardingEventListener listenerProxy;
+
+ public DefaultForwarderFactory() {
+ listenerProxy = EventListenerUtils.proxyWrapper(PortForwardingEventListener.class, getClass().getClassLoader(), listeners);
+ }
+
+ @Override
+ public PortForwardingEventListener getPortForwardingEventListenerProxy() {
+ return listenerProxy;
+ }
+
+ @Override
+ public void addPortForwardingEventListener(PortForwardingEventListener listener) {
+ listeners.add(PortForwardingEventListener.validateListener(listener));
+ }
+
+ @Override
+ public void removePortForwardingEventListener(PortForwardingEventListener listener) {
+ if (listener == null) {
+ return;
+ }
+
+ listeners.remove(PortForwardingEventListener.validateListener(listener));
+ }
+
+ @Override
+ public ForwardingFilter create(ConnectionService service) {
+ ForwardingFilter forwarder = new DefaultForwardingFilter(service);
+ forwarder.addPortForwardingEventListenerManager(this);
+ return forwarder;
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/aa551bc0/sshd-core/src/main/java/org/apache/sshd/common/forward/DefaultForwardingFilter.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/forward/DefaultForwardingFilter.java b/sshd-core/src/main/java/org/apache/sshd/common/forward/DefaultForwardingFilter.java
new file mode 100644
index 0000000..64f37db
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/common/forward/DefaultForwardingFilter.java
@@ -0,0 +1,1003 @@
+/*
+ * 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.io.OutputStream;
+import java.net.InetSocketAddress;
+import java.net.SocketAddress;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.EnumSet;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.concurrent.CopyOnWriteArraySet;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.sshd.client.channel.ClientChannelEvent;
+import org.apache.sshd.common.Closeable;
+import org.apache.sshd.common.Factory;
+import org.apache.sshd.common.FactoryManager;
+import org.apache.sshd.common.RuntimeSshException;
+import org.apache.sshd.common.SshConstants;
+import org.apache.sshd.common.SshException;
+import org.apache.sshd.common.io.IoAcceptor;
+import org.apache.sshd.common.io.IoHandler;
+import org.apache.sshd.common.io.IoHandlerFactory;
+import org.apache.sshd.common.io.IoServiceFactory;
+import org.apache.sshd.common.io.IoSession;
+import org.apache.sshd.common.session.ConnectionService;
+import org.apache.sshd.common.session.Session;
+import org.apache.sshd.common.session.SessionHolder;
+import org.apache.sshd.common.util.EventListenerUtils;
+import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.common.util.Invoker;
+import org.apache.sshd.common.util.Readable;
+import org.apache.sshd.common.util.ValidateUtils;
+import org.apache.sshd.common.util.buffer.Buffer;
+import org.apache.sshd.common.util.buffer.ByteArrayBuffer;
+import org.apache.sshd.common.util.closeable.AbstractInnerCloseable;
+import org.apache.sshd.common.util.net.SshdSocketAddress;
+import org.apache.sshd.server.forward.TcpForwardingFilter;
+
+/**
+ * Requests a "tcpip-forward" action
+ *
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class DefaultForwardingFilter
+ extends AbstractInnerCloseable
+ implements ForwardingFilter, SessionHolder<Session>, PortForwardingEventListenerManager {
+
+ /**
+ * Used to configure the timeout (milliseconds) for receiving a response
+ * for the forwarding request
+ *
+ * @see #DEFAULT_FORWARD_REQUEST_TIMEOUT
+ */
+ public static final String FORWARD_REQUEST_TIMEOUT = "tcpip-forward-request-timeout";
+
+ /**
+ * Default value for {@link #FORWARD_REQUEST_TIMEOUT} if none specified
+ */
+ public static final long DEFAULT_FORWARD_REQUEST_TIMEOUT = TimeUnit.SECONDS.toMillis(15L);
+
+ public static final Set<ClientChannelEvent> STATIC_IO_MSG_RECEIVED_EVENTS =
+ Collections.unmodifiableSet(EnumSet.of(ClientChannelEvent.OPENED, ClientChannelEvent.CLOSED));
+
+ private final ConnectionService service;
+ private final IoHandlerFactory socksProxyIoHandlerFactory = () -> new SocksProxy(getConnectionService());
+ private final Session sessionInstance;
+ private final Map<Integer, SshdSocketAddress> localToRemote = new TreeMap<>(Comparator.naturalOrder());
+ private final Map<Integer, SshdSocketAddress> remoteToLocal = new TreeMap<>(Comparator.naturalOrder());
+ private final Map<Integer, SocksProxy> dynamicLocal = new TreeMap<>(Comparator.naturalOrder());
+ private final Set<LocalForwardingEntry> localForwards = new HashSet<>();
+ private final IoHandlerFactory staticIoHandlerFactory = StaticIoHandler::new;
+ private final Collection<PortForwardingEventListener> listeners = new CopyOnWriteArraySet<>();
+ private final Collection<PortForwardingEventListenerManager> managersHolder = new CopyOnWriteArraySet<>();
+ private final PortForwardingEventListener listenerProxy;
+
+ private IoAcceptor acceptor;
+
+ public DefaultForwardingFilter(ConnectionService service) {
+ this.service = Objects.requireNonNull(service, "No connection service");
+ this.sessionInstance = Objects.requireNonNull(service.getSession(), "No session");
+ this.listenerProxy = EventListenerUtils.proxyWrapper(PortForwardingEventListener.class, getClass().getClassLoader(), listeners);
+ }
+
+ @Override
+ public PortForwardingEventListener getPortForwardingEventListenerProxy() {
+ return listenerProxy;
+ }
+
+ @Override
+ public void addPortForwardingEventListener(PortForwardingEventListener listener) {
+ listeners.add(PortForwardingEventListener.validateListener(listener));
+ }
+
+ @Override
+ public void removePortForwardingEventListener(PortForwardingEventListener listener) {
+ if (listener == null) {
+ return;
+ }
+
+ listeners.remove(PortForwardingEventListener.validateListener(listener));
+ }
+
+ @Override
+ public Collection<PortForwardingEventListenerManager> getRegisteredManagers() {
+ return managersHolder.isEmpty() ? Collections.emptyList() : new ArrayList<>(managersHolder);
+ }
+
+ @Override
+ public boolean addPortForwardingEventListenerManager(PortForwardingEventListenerManager manager) {
+ return managersHolder.add(Objects.requireNonNull(manager, "No manager"));
+ }
+
+ @Override
+ public boolean removePortForwardingEventListenerManager(PortForwardingEventListenerManager manager) {
+ if (manager == null) {
+ return false;
+ }
+
+ return managersHolder.remove(manager);
+ }
+
+ @Override
+ public Session getSession() {
+ return sessionInstance;
+ }
+
+ public final ConnectionService getConnectionService() {
+ return service;
+ }
+
+ protected Collection<PortForwardingEventListener> getDefaultListeners() {
+ Collection<PortForwardingEventListener> defaultListeners = new ArrayList<>();
+ defaultListeners.add(getPortForwardingEventListenerProxy());
+
+ Session session = getSession();
+ PortForwardingEventListener l = session.getPortForwardingEventListenerProxy();
+ if (l != null) {
+ defaultListeners.add(l);
+ }
+
+ FactoryManager manager = (session == null) ? null : session.getFactoryManager();
+ l = (manager == null) ? null : manager.getPortForwardingEventListenerProxy();
+ if (l != null) {
+ defaultListeners.add(l);
+ }
+
+ return defaultListeners;
+ }
+
+ @Override
+ public synchronized SshdSocketAddress startLocalPortForwarding(SshdSocketAddress local, SshdSocketAddress remote) throws IOException {
+ Objects.requireNonNull(local, "Local address is null");
+ ValidateUtils.checkTrue(local.getPort() >= 0, "Invalid local port: %s", local);
+ Objects.requireNonNull(remote, "Remote address is null");
+
+ if (isClosed()) {
+ throw new IllegalStateException("TcpipForwarder is closed");
+ }
+ if (isClosing()) {
+ throw new IllegalStateException("TcpipForwarder is closing");
+ }
+
+ InetSocketAddress bound;
+ int port;
+ signalEstablishingExplicitTunnel(local, remote, true);
+ try {
+ bound = doBind(local, staticIoHandlerFactory);
+ port = bound.getPort();
+ SshdSocketAddress prev;
+ synchronized (localToRemote) {
+ prev = localToRemote.put(port, remote);
+ }
+
+ if (prev != null) {
+ throw new IOException("Multiple local port forwarding bindings on port=" + port + ": current=" + remote + ", previous=" + prev);
+ }
+ } catch (IOException | RuntimeException e) {
+ try {
+ stopLocalPortForwarding(local);
+ } catch (IOException | RuntimeException err) {
+ e.addSuppressed(err);
+ }
+ signalEstablishedExplicitTunnel(local, remote, true, null, e);
+ throw e;
+ }
+
+ try {
+ SshdSocketAddress result = new SshdSocketAddress(bound.getHostString(), port);
+ if (log.isDebugEnabled()) {
+ log.debug("startLocalPortForwarding(" + local + " -> " + remote + "): " + result);
+ }
+ signalEstablishedExplicitTunnel(local, remote, true, result, null);
+ return result;
+ } catch (IOException | RuntimeException e) {
+ stopLocalPortForwarding(local);
+ throw e;
+ }
+ }
+
+ @Override
+ public synchronized void stopLocalPortForwarding(SshdSocketAddress local) throws IOException {
+ Objects.requireNonNull(local, "Local address is null");
+
+ SshdSocketAddress bound;
+ synchronized (localToRemote) {
+ bound = localToRemote.remove(local.getPort());
+ }
+
+ if ((bound != null) && (acceptor != null)) {
+ if (log.isDebugEnabled()) {
+ log.debug("stopLocalPortForwarding(" + local + ") unbind " + bound);
+ }
+
+ signalTearingDownExplicitTunnel(bound, true);
+ try {
+ acceptor.unbind(bound.toInetSocketAddress());
+ } catch (RuntimeException e) {
+ signalTornDownExplicitTunnel(bound, true, e);
+ throw e;
+ }
+
+ signalTornDownExplicitTunnel(bound, true, null);
+ } else {
+ if (log.isDebugEnabled()) {
+ log.debug("stopLocalPortForwarding(" + local + ") no mapping/acceptor for " + bound);
+ }
+ }
+ }
+
+ @Override
+ public synchronized SshdSocketAddress startRemotePortForwarding(SshdSocketAddress remote, SshdSocketAddress local) throws IOException {
+ Objects.requireNonNull(local, "Local address is null");
+ Objects.requireNonNull(remote, "Remote address is null");
+
+ String remoteHost = remote.getHostName();
+ int remotePort = remote.getPort();
+ Session session = getSession();
+ Buffer buffer = session.createBuffer(SshConstants.SSH_MSG_GLOBAL_REQUEST, remoteHost.length() + Long.SIZE);
+ buffer.putString("tcpip-forward");
+ buffer.putBoolean(true); // want reply
+ buffer.putString(remoteHost);
+ buffer.putInt(remotePort);
+
+ long timeout = session.getLongProperty(FORWARD_REQUEST_TIMEOUT, DEFAULT_FORWARD_REQUEST_TIMEOUT);
+ Buffer result;
+ int port;
+ signalEstablishingExplicitTunnel(local, remote, false);
+ try {
+ result = session.request("tcpip-forward", buffer, timeout, TimeUnit.MILLISECONDS);
+ if (result == null) {
+ throw new SshException("Tcpip forwarding request denied by server");
+ }
+ port = (remotePort == 0) ? result.getInt() : remote.getPort();
+ // TODO: Is it really safe to only store the local address after the request ?
+ SshdSocketAddress prev;
+ synchronized (remoteToLocal) {
+ prev = remoteToLocal.put(port, local);
+ }
+
+ if (prev != null) {
+ throw new IOException("Multiple remote port forwarding bindings on port=" + port + ": current=" + remote + ", previous=" + prev);
+ }
+ } catch (IOException | RuntimeException e) {
+ try {
+ stopRemotePortForwarding(remote);
+ } catch (IOException | RuntimeException err) {
+ e.addSuppressed(err);
+ }
+ signalEstablishedExplicitTunnel(local, remote, false, null, e);
+ throw e;
+ }
+
+ try {
+ SshdSocketAddress bound = new SshdSocketAddress(remoteHost, port);
+ if (log.isDebugEnabled()) {
+ log.debug("startRemotePortForwarding(" + remote + " -> " + local + "): " + bound);
+ }
+
+ signalEstablishedExplicitTunnel(local, remote, false, bound, null);
+ return bound;
+ } catch (IOException | RuntimeException e) {
+ stopRemotePortForwarding(remote);
+ throw e;
+ }
+ }
+
+ @Override
+ public synchronized void stopRemotePortForwarding(SshdSocketAddress remote) throws IOException {
+ SshdSocketAddress bound;
+ synchronized (remoteToLocal) {
+ bound = remoteToLocal.remove(remote.getPort());
+ }
+
+ if (bound != null) {
+ if (log.isDebugEnabled()) {
+ log.debug("stopRemotePortForwarding(" + remote + ") cancel forwarding to " + bound);
+ }
+
+ String remoteHost = remote.getHostName();
+ Session session = getSession();
+ Buffer buffer = session.createBuffer(SshConstants.SSH_MSG_GLOBAL_REQUEST, remoteHost.length() + Long.SIZE);
+ buffer.putString("cancel-tcpip-forward");
+ buffer.putBoolean(false); // want reply
+ buffer.putString(remoteHost);
+ buffer.putInt(remote.getPort());
+
+ signalTearingDownExplicitTunnel(bound, false);
+ try {
+ session.writePacket(buffer);
+ } catch (IOException | RuntimeException e) {
+ signalTornDownExplicitTunnel(bound, false, e);
+ throw e;
+ }
+
+ signalTornDownExplicitTunnel(bound, false, null);
+ } else {
+ if (log.isDebugEnabled()) {
+ log.debug("stopRemotePortForwarding(" + remote + ") no binding found");
+ }
+ }
+ }
+
+ protected void signalTearingDownExplicitTunnel(SshdSocketAddress boundAddress, boolean localForwarding) throws IOException {
+ try {
+ invokePortEventListenerSignaller(l -> {
+ signalTearingDownExplicitTunnel(l, boundAddress, localForwarding);
+ return null;
+ });
+ } catch (Throwable t) {
+ if (t instanceof RuntimeException) {
+ throw (RuntimeException) t;
+ } else if (t instanceof Error) {
+ throw (Error) t;
+ } else if (t instanceof IOException) {
+ throw (IOException) t;
+ } else {
+ throw new IOException("Failed (" + t.getClass().getSimpleName() + ")"
+ + " to signal tearing down explicit tunnel for local=" + localForwarding
+ + " on bound=" + boundAddress, t);
+ }
+ }
+ }
+
+ protected void signalTearingDownExplicitTunnel(
+ PortForwardingEventListener listener, SshdSocketAddress boundAddress, boolean localForwarding)
+ throws IOException {
+ if (listener == null) {
+ return;
+ }
+
+ listener.tearingDownExplicitTunnel(getSession(), boundAddress, localForwarding);
+ }
+
+ protected void signalTornDownExplicitTunnel(SshdSocketAddress boundAddress, boolean localForwarding, Throwable reason) throws IOException {
+ try {
+ invokePortEventListenerSignaller(l -> {
+ signalTornDownExplicitTunnel(l, boundAddress, localForwarding, reason);
+ return null;
+ });
+ } catch (Throwable t) {
+ if (t instanceof RuntimeException) {
+ throw (RuntimeException) t;
+ } else if (t instanceof Error) {
+ throw (Error) t;
+ } else if (t instanceof IOException) {
+ throw (IOException) t;
+ } else {
+ throw new IOException("Failed (" + t.getClass().getSimpleName() + ")"
+ + " to signal torn down explicit tunnel local=" + localForwarding
+ + " on bound=" + boundAddress, t);
+ }
+ }
+ }
+
+ protected void signalTornDownExplicitTunnel(
+ PortForwardingEventListener listener, SshdSocketAddress boundAddress, boolean localForwarding, Throwable reason)
+ throws IOException {
+ if (listener == null) {
+ return;
+ }
+
+ listener.tornDownExplicitTunnel(getSession(), boundAddress, localForwarding, reason);
+ }
+
+ @Override
+ public synchronized SshdSocketAddress startDynamicPortForwarding(SshdSocketAddress local) throws IOException {
+ Objects.requireNonNull(local, "Local address is null");
+ ValidateUtils.checkTrue(local.getPort() >= 0, "Invalid local port: %s", local);
+
+ if (isClosed()) {
+ throw new IllegalStateException("TcpipForwarder is closed");
+ }
+ if (isClosing()) {
+ throw new IllegalStateException("TcpipForwarder is closing");
+ }
+
+ SocksProxy socksProxy = new SocksProxy(service);
+ SocksProxy prev;
+ InetSocketAddress bound;
+ int port;
+ signalEstablishingDynamicTunnel(local);
+ try {
+ bound = doBind(local, socksProxyIoHandlerFactory);
+ port = bound.getPort();
+ synchronized (dynamicLocal) {
+ prev = dynamicLocal.put(port, socksProxy);
+ }
+
+ if (prev != null) {
+ throw new IOException("Multiple dynamic port mappings found for port=" + port + ": current=" + socksProxy + ", previous=" + prev);
+ }
+ } catch (IOException | RuntimeException e) {
+ try {
+ stopDynamicPortForwarding(local);
+ } catch (IOException | RuntimeException err) {
+ e.addSuppressed(err);
+ }
+ signalEstablishedDynamicTunnel(local, null, e);
+ throw e;
+ }
+
+ try {
+ SshdSocketAddress result = new SshdSocketAddress(bound.getHostString(), port);
+ if (log.isDebugEnabled()) {
+ log.debug("startDynamicPortForwarding(" + local + "): " + result);
+ }
+
+ signalEstablishedDynamicTunnel(local, result, null);
+ return result;
+ } catch (IOException | RuntimeException e) {
+ stopDynamicPortForwarding(local);
+ throw e;
+ }
+ }
+
+ protected void signalEstablishedDynamicTunnel(
+ SshdSocketAddress local, SshdSocketAddress boundAddress, Throwable reason)
+ throws IOException {
+ try {
+ invokePortEventListenerSignaller(l -> {
+ signalEstablishedDynamicTunnel(l, local, boundAddress, reason);
+ return null;
+ });
+ } catch (Throwable t) {
+ if (t instanceof RuntimeException) {
+ throw (RuntimeException) t;
+ } else if (t instanceof Error) {
+ throw (Error) t;
+ } else if (t instanceof IOException) {
+ throw (IOException) t;
+ } else {
+ throw new IOException("Failed (" + t.getClass().getSimpleName() + ")"
+ + " to signal establishing dynamic tunnel for local=" + local
+ + " on bound=" + boundAddress, t);
+ }
+ }
+ }
+
+ protected void signalEstablishedDynamicTunnel(PortForwardingEventListener listener,
+ SshdSocketAddress local, SshdSocketAddress boundAddress, Throwable reason)
+ throws IOException {
+ if (listener == null) {
+ return;
+ }
+
+ listener.establishedDynamicTunnel(getSession(), local, boundAddress, reason);
+ }
+
+ protected void signalEstablishingDynamicTunnel(SshdSocketAddress local) throws IOException {
+ try {
+ invokePortEventListenerSignaller(l -> {
+ signalEstablishingDynamicTunnel(l, local);
+ return null;
+ });
+ } catch (Throwable t) {
+ if (t instanceof RuntimeException) {
+ throw (RuntimeException) t;
+ } else if (t instanceof Error) {
+ throw (Error) t;
+ } else if (t instanceof IOException) {
+ throw (IOException) t;
+ } else {
+ throw new IOException("Failed (" + t.getClass().getSimpleName() + ")"
+ + " to signal establishing dynamic tunnel for local=" + local, t);
+ }
+ }
+ }
+
+ protected void signalEstablishingDynamicTunnel(PortForwardingEventListener listener, SshdSocketAddress local) throws IOException {
+ if (listener == null) {
+ return;
+ }
+
+ listener.establishingDynamicTunnel(getSession(), local);
+ }
+
+ @Override
+ public synchronized void stopDynamicPortForwarding(SshdSocketAddress local) throws IOException {
+ SocksProxy obj;
+ synchronized (dynamicLocal) {
+ obj = dynamicLocal.remove(local.getPort());
+ }
+
+ if (obj != null) {
+ if (log.isDebugEnabled()) {
+ log.debug("stopDynamicPortForwarding(" + local + ") unbinding");
+ }
+
+ signalTearingDownDynamicTunnel(local);
+ try {
+ obj.close(true);
+ acceptor.unbind(local.toInetSocketAddress());
+ } catch (RuntimeException e) {
+ signalTornDownDynamicTunnel(local, e);
+ throw e;
+ }
+
+ signalTornDownDynamicTunnel(local, null);
+ } else {
+ if (log.isDebugEnabled()) {
+ log.debug("stopDynamicPortForwarding(" + local + ") no binding found");
+ }
+ }
+ }
+
+ protected void signalTearingDownDynamicTunnel(SshdSocketAddress address) throws IOException {
+ try {
+ invokePortEventListenerSignaller(l -> {
+ signalTearingDownDynamicTunnel(l, address);
+ return null;
+ });
+ } catch (Throwable t) {
+ if (t instanceof RuntimeException) {
+ throw (RuntimeException) t;
+ } else if (t instanceof Error) {
+ throw (Error) t;
+ } else if (t instanceof IOException) {
+ throw (IOException) t;
+ } else {
+ throw new IOException("Failed (" + t.getClass().getSimpleName() + ")"
+ + " to signal tearing down dynamic tunnel for address=" + address, t);
+ }
+ }
+ }
+
+ protected void signalTearingDownDynamicTunnel(PortForwardingEventListener listener, SshdSocketAddress address) throws IOException {
+ if (listener == null) {
+ return;
+ }
+
+ listener.tearingDownDynamicTunnel(getSession(), address);
+ }
+
+ protected void signalTornDownDynamicTunnel(SshdSocketAddress address, Throwable reason) throws IOException {
+ try {
+ invokePortEventListenerSignaller(l -> {
+ signalTornDownDynamicTunnel(l, address, reason);
+ return null;
+ });
+ } catch (Throwable t) {
+ if (t instanceof RuntimeException) {
+ throw (RuntimeException) t;
+ } else if (t instanceof Error) {
+ throw (Error) t;
+ } else if (t instanceof IOException) {
+ throw (IOException) t;
+ } else {
+ throw new IOException("Failed (" + t.getClass().getSimpleName() + ")"
+ + " to signal torn down dynamic tunnel for address=" + address, t);
+ }
+ }
+ }
+
+ protected void signalTornDownDynamicTunnel(
+ PortForwardingEventListener listener, SshdSocketAddress address, Throwable reason)
+ throws IOException {
+ if (listener == null) {
+ return;
+ }
+
+ listener.tornDownDynamicTunnel(getSession(), address, reason);
+ }
+
+ @Override
+ public synchronized SshdSocketAddress getForwardedPort(int remotePort) {
+ synchronized (remoteToLocal) {
+ return remoteToLocal.get(remotePort);
+ }
+ }
+
+ @Override
+ public synchronized SshdSocketAddress localPortForwardingRequested(SshdSocketAddress local) throws IOException {
+ Objects.requireNonNull(local, "Local address is null");
+ ValidateUtils.checkTrue(local.getPort() >= 0, "Invalid local port: %s", local);
+
+ Session session = getSession();
+ FactoryManager manager = Objects.requireNonNull(session.getFactoryManager(), "No factory manager");
+ TcpForwardingFilter filter = manager.getTcpForwardingFilter();
+ try {
+ if ((filter == null) || (!filter.canListen(local, session))) {
+ if (log.isDebugEnabled()) {
+ log.debug("localPortForwardingRequested(" + session + ")[" + local + "][haveFilter=" + (filter != null) + "] rejected");
+ }
+ return null;
+ }
+ } catch (Error e) {
+ log.warn("localPortForwardingRequested({})[{}] failed ({}) to consult forwarding filter: {}",
+ session, local, e.getClass().getSimpleName(), e.getMessage());
+ if (log.isDebugEnabled()) {
+ log.debug("localPortForwardingRequested(" + this + ")[" + local + "] filter consultation failure details", e);
+ }
+ throw new RuntimeSshException(e);
+ }
+
+ signalEstablishingExplicitTunnel(local, null, true);
+ SshdSocketAddress result;
+ try {
+ InetSocketAddress bound = doBind(local, staticIoHandlerFactory);
+ result = new SshdSocketAddress(bound.getHostString(), bound.getPort());
+ if (log.isDebugEnabled()) {
+ log.debug("localPortForwardingRequested(" + local + "): " + result);
+ }
+
+ boolean added;
+ synchronized (localForwards) {
+ // NOTE !!! it is crucial to use the bound address host name first
+ added = localForwards.add(new LocalForwardingEntry(result.getHostName(), local.getHostName(), result.getPort()));
+ }
+
+ if (!added) {
+ throw new IOException("Failed to add local port forwarding entry for " + local + " -> " + result);
+ }
+ } catch (IOException | RuntimeException e) {
+ try {
+ localPortForwardingCancelled(local);
+ } catch (IOException | RuntimeException err) {
+ e.addSuppressed(e);
+ }
+ signalEstablishedExplicitTunnel(local, null, true, null, e);
+ throw e;
+ }
+
+ try {
+ signalEstablishedExplicitTunnel(local, null, true, result, null);
+ return result;
+ } catch (IOException | RuntimeException e) {
+ throw e;
+ }
+ }
+
+ @Override
+ public synchronized void localPortForwardingCancelled(SshdSocketAddress local) throws IOException {
+ LocalForwardingEntry entry;
+ synchronized (localForwards) {
+ entry = LocalForwardingEntry.findMatchingEntry(local.getHostName(), local.getPort(), localForwards);
+ if (entry != null) {
+ localForwards.remove(entry);
+ }
+ }
+
+ if ((entry != null) && (acceptor != null)) {
+ if (log.isDebugEnabled()) {
+ log.debug("localPortForwardingCancelled(" + local + ") unbind " + entry);
+ }
+
+ signalTearingDownExplicitTunnel(entry, true);
+ try {
+ acceptor.unbind(entry.toInetSocketAddress());
+ } catch (RuntimeException e) {
+ signalTornDownExplicitTunnel(entry, true, e);
+ throw e;
+ }
+
+ signalTornDownExplicitTunnel(entry, true, null);
+ } else {
+ if (log.isDebugEnabled()) {
+ log.debug("localPortForwardingCancelled(" + local + ") no match/acceptor: " + entry);
+ }
+ }
+ }
+
+ protected void signalEstablishingExplicitTunnel(
+ SshdSocketAddress local, SshdSocketAddress remote, boolean localForwarding)
+ throws IOException {
+ try {
+ invokePortEventListenerSignaller(l -> {
+ signalEstablishingExplicitTunnel(l, local, remote, localForwarding);
+ return null;
+ });
+ } catch (Throwable t) {
+ if (t instanceof RuntimeException) {
+ throw (RuntimeException) t;
+ } else if (t instanceof Error) {
+ throw (Error) t;
+ } else if (t instanceof IOException) {
+ throw (IOException) t;
+ } else {
+ throw new IOException("Failed (" + t.getClass().getSimpleName() + ")"
+ + " to signal establishing explicit tunnel for local=" + local
+ + ", remote=" + remote + ", localForwarding=" + localForwarding, t);
+ }
+ }
+ }
+
+ protected void signalEstablishingExplicitTunnel(PortForwardingEventListener listener,
+ SshdSocketAddress local, SshdSocketAddress remote, boolean localForwarding)
+ throws IOException {
+ if (listener == null) {
+ return;
+ }
+
+ listener.establishingExplicitTunnel(getSession(), local, remote, localForwarding);
+ }
+
+ protected void signalEstablishedExplicitTunnel(
+ SshdSocketAddress local, SshdSocketAddress remote, boolean localForwarding,
+ SshdSocketAddress boundAddress, Throwable reason)
+ throws IOException {
+ try {
+ invokePortEventListenerSignaller(l -> {
+ signalEstablishedExplicitTunnel(l, local, remote, localForwarding, boundAddress, reason);
+ return null;
+ });
+ } catch (Throwable t) {
+ if (t instanceof RuntimeException) {
+ throw (RuntimeException) t;
+ } else if (t instanceof Error) {
+ throw (Error) t;
+ } else if (t instanceof IOException) {
+ throw (IOException) t;
+ } else {
+ throw new IOException("Failed (" + t.getClass().getSimpleName() + ")"
+ + " to signal established explicit tunnel for local=" + local
+ + ", remote=" + remote + ", localForwarding=" + localForwarding
+ + ", bound=" + boundAddress, t);
+ }
+ }
+ }
+
+ protected void signalEstablishedExplicitTunnel(PortForwardingEventListener listener,
+ SshdSocketAddress local, SshdSocketAddress remote, boolean localForwarding,
+ SshdSocketAddress boundAddress, Throwable reason)
+ throws IOException {
+ if (listener == null) {
+ return;
+ }
+
+ listener.establishedExplicitTunnel(getSession(), local, remote, localForwarding, boundAddress, reason);
+ }
+
+ protected void invokePortEventListenerSignaller(Invoker<PortForwardingEventListener, Void> invoker) throws Throwable {
+ Throwable err = null;
+ try {
+ invokePortEventListenerSignallerListeners(getDefaultListeners(), invoker);
+ } catch (Throwable t) {
+ Throwable e = GenericUtils.peelException(t);
+ err = GenericUtils.accumulateException(err, e);
+ }
+
+ try {
+ invokePortEventListenerSignallerHolders(managersHolder, invoker);
+ } catch (Throwable t) {
+ Throwable e = GenericUtils.peelException(t);
+ err = GenericUtils.accumulateException(err, e);
+ }
+
+
+ if (err != null) {
+ throw err;
+ }
+ }
+
+ protected void invokePortEventListenerSignallerListeners(
+ Collection<? extends PortForwardingEventListener> listeners, Invoker<PortForwardingEventListener, Void> invoker)
+ throws Throwable {
+ if (GenericUtils.isEmpty(listeners)) {
+ return;
+ }
+
+ Throwable err = null;
+ // Need to go over the hierarchy (session, factory managed, connection service, etc...)
+ for (PortForwardingEventListener l : listeners) {
+ if (l == null) {
+ continue;
+ }
+
+ try {
+ invoker.invoke(l);
+ } catch (Throwable t) {
+ Throwable e = GenericUtils.peelException(t);
+ err = GenericUtils.accumulateException(err, e);
+ }
+ }
+
+ if (err != null) {
+ throw err;
+ }
+ }
+
+ protected void invokePortEventListenerSignallerHolders(
+ Collection<? extends PortForwardingEventListenerManager> holders, Invoker<PortForwardingEventListener, Void> invoker)
+ throws Throwable {
+ if (GenericUtils.isEmpty(holders)) {
+ return;
+ }
+
+ Throwable err = null;
+ // Need to go over the hierarchy (session, factory managed, connection service, etc...)
+ for (PortForwardingEventListenerManager m : holders) {
+ try {
+ PortForwardingEventListener listener = m.getPortForwardingEventListenerProxy();
+ if (listener != null) {
+ invoker.invoke(listener);
+ }
+ } catch (Throwable t) {
+ Throwable e = GenericUtils.peelException(t);
+ err = GenericUtils.accumulateException(err, e);
+ }
+
+ if (m instanceof PortForwardingEventListenerManagerHolder) {
+ try {
+ invokePortEventListenerSignallerHolders(((PortForwardingEventListenerManagerHolder) m).getRegisteredManagers(), invoker);
+ } catch (Throwable t) {
+ Throwable e = GenericUtils.peelException(t);
+ err = GenericUtils.accumulateException(err, e);
+ }
+ }
+ }
+
+ if (err != null) {
+ throw err;
+ }
+ }
+
+ @Override
+ protected synchronized Closeable getInnerCloseable() {
+ return builder().parallel(dynamicLocal.values()).close(acceptor).build();
+ }
+
+ @Override
+ protected void preClose() {
+ this.listeners.clear();
+ this.managersHolder.clear();
+ super.preClose();
+ }
+
+ /**
+ * @param address The request bind address
+ * @param handlerFactory A {@link Factory} to create an {@link IoHandler} if necessary
+ * @return The {@link InetSocketAddress} to which the binding occurred
+ * @throws IOException If failed to bind
+ */
+ private InetSocketAddress doBind(SshdSocketAddress address, Factory<? extends IoHandler> handlerFactory) throws IOException {
+ if (acceptor == null) {
+ Session session = getSession();
+ FactoryManager manager = Objects.requireNonNull(session.getFactoryManager(), "No factory manager");
+ IoServiceFactory factory = Objects.requireNonNull(manager.getIoServiceFactory(), "No I/O service factory");
+ IoHandler handler = handlerFactory.create();
+ acceptor = factory.createAcceptor(handler);
+ }
+
+ // TODO find a better way to determine the resulting bind address - what if multi-threaded calls...
+ Set<SocketAddress> before = acceptor.getBoundAddresses();
+ try {
+ InetSocketAddress bindAddress = address.toInetSocketAddress();
+ acceptor.bind(bindAddress);
+
+ Set<SocketAddress> after = acceptor.getBoundAddresses();
+ if (GenericUtils.size(after) > 0) {
+ after.removeAll(before);
+ }
+ if (GenericUtils.isEmpty(after)) {
+ throw new IOException("Error binding to " + address + "[" + bindAddress + "]: no local addresses bound");
+ }
+
+ if (after.size() > 1) {
+ throw new IOException("Multiple local addresses have been bound for " + address + "[" + bindAddress + "]");
+ }
+ return (InetSocketAddress) after.iterator().next();
+ } catch (IOException bindErr) {
+ Set<SocketAddress> after = acceptor.getBoundAddresses();
+ if (GenericUtils.isEmpty(after)) {
+ close();
+ }
+ throw bindErr;
+ }
+ }
+
+ @Override
+ public String toString() {
+ return getClass().getSimpleName() + "[" + getSession() + "]";
+ }
+
+ //
+ // Static IoHandler implementation
+ //
+
+ class StaticIoHandler implements IoHandler {
+ StaticIoHandler() {
+ super();
+ }
+
+ @Override
+ @SuppressWarnings("synthetic-access")
+ public void sessionCreated(final IoSession session) throws Exception {
+ InetSocketAddress local = (InetSocketAddress) session.getLocalAddress();
+ int localPort = local.getPort();
+ SshdSocketAddress remote = localToRemote.get(localPort);
+ if (log.isDebugEnabled()) {
+ log.debug("sessionCreated({}) remote={}", session, remote);
+ }
+
+ final TcpipClientChannel channel;
+ if (remote != null) {
+ 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(future -> {
+ Throwable t = future.getException();
+ if (t != null) {
+ log.warn("Failed ({}) to open channel for session={}: {}",
+ t.getClass().getSimpleName(), session, t.getMessage());
+ if (log.isDebugEnabled()) {
+ log.debug("sessionCreated(" + session + ") channel=" + channel + " open failure details", t);
+ }
+ DefaultForwardingFilter.this.service.unregisterChannel(channel);
+ channel.close(false);
+ }
+ });
+ }
+
+ @Override
+ @SuppressWarnings("synthetic-access")
+ public void sessionClosed(IoSession session) throws Exception {
+ TcpipClientChannel channel = (TcpipClientChannel) session.getAttribute(TcpipClientChannel.class);
+ if (channel != null) {
+ if (log.isDebugEnabled()) {
+ log.debug("sessionClosed({}) closing channel={}", session, channel);
+ }
+ channel.close(false);
+ }
+ }
+
+ @Override
+ @SuppressWarnings("synthetic-access")
+ public void messageReceived(IoSession session, Readable message) throws Exception {
+ TcpipClientChannel channel = (TcpipClientChannel) session.getAttribute(TcpipClientChannel.class);
+ Buffer buffer = new ByteArrayBuffer(message.available() + Long.SIZE, false);
+ buffer.putBuffer(message);
+
+ Collection<ClientChannelEvent> result = channel.waitFor(STATIC_IO_MSG_RECEIVED_EVENTS, Long.MAX_VALUE);
+ if (log.isTraceEnabled()) {
+ log.trace("messageReceived({}) channel={}, len={} wait result: {}",
+ session, channel, result, buffer.array());
+ }
+
+ OutputStream outputStream = channel.getInvertedIn();
+ outputStream.write(buffer.array(), buffer.rpos(), buffer.available());
+ outputStream.flush();
+ }
+
+ @Override
+ @SuppressWarnings("synthetic-access")
+ public void exceptionCaught(IoSession session, Throwable cause) throws Exception {
+ if (log.isDebugEnabled()) {
+ log.debug("exceptionCaught({}) {}: {}", session, cause.getClass().getSimpleName(), cause.getMessage());
+ }
+ if (log.isTraceEnabled()) {
+ log.trace("exceptionCaught(" + session + ") caught exception details", cause);
+ }
+ session.close(false);
+ }
+ }
+}
[2/3] mina-sshd git commit: [SSHD-766] Separate forwarding filter
functionality according to sshd-config options
Posted by lg...@apache.org.
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/aa551bc0/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
deleted file mode 100644
index 23fe01c..0000000
--- a/sshd-core/src/main/java/org/apache/sshd/common/forward/DefaultTcpipForwarder.java
+++ /dev/null
@@ -1,1007 +0,0 @@
-/*
- * 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.io.OutputStream;
-import java.net.InetSocketAddress;
-import java.net.SocketAddress;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.EnumSet;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Set;
-import java.util.TreeMap;
-import java.util.concurrent.CopyOnWriteArraySet;
-import java.util.concurrent.TimeUnit;
-
-import org.apache.sshd.client.channel.ClientChannelEvent;
-import org.apache.sshd.common.Closeable;
-import org.apache.sshd.common.Factory;
-import org.apache.sshd.common.FactoryManager;
-import org.apache.sshd.common.RuntimeSshException;
-import org.apache.sshd.common.SshConstants;
-import org.apache.sshd.common.SshException;
-import org.apache.sshd.common.io.IoAcceptor;
-import org.apache.sshd.common.io.IoHandler;
-import org.apache.sshd.common.io.IoHandlerFactory;
-import org.apache.sshd.common.io.IoServiceFactory;
-import org.apache.sshd.common.io.IoSession;
-import org.apache.sshd.common.session.ConnectionService;
-import org.apache.sshd.common.session.Session;
-import org.apache.sshd.common.session.SessionHolder;
-import org.apache.sshd.common.util.EventListenerUtils;
-import org.apache.sshd.common.util.GenericUtils;
-import org.apache.sshd.common.util.Invoker;
-import org.apache.sshd.common.util.Readable;
-import org.apache.sshd.common.util.ValidateUtils;
-import org.apache.sshd.common.util.buffer.Buffer;
-import org.apache.sshd.common.util.buffer.ByteArrayBuffer;
-import org.apache.sshd.common.util.closeable.AbstractInnerCloseable;
-import org.apache.sshd.common.util.net.SshdSocketAddress;
-import org.apache.sshd.server.forward.ForwardingFilter;
-
-/**
- * Requests a "tcpip-forward" action
- *
- * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
- */
-public class DefaultTcpipForwarder
- extends AbstractInnerCloseable
- implements TcpipForwarder, SessionHolder<Session>, PortForwardingEventListenerManager {
-
- /**
- * Used to configure the timeout (milliseconds) for receiving a response
- * for the forwarding request
- *
- * @see #DEFAULT_FORWARD_REQUEST_TIMEOUT
- */
- public static final String FORWARD_REQUEST_TIMEOUT = "tcpip-forward-request-timeout";
-
- /**
- * Default value for {@link #FORWARD_REQUEST_TIMEOUT} if none specified
- */
- public static final long DEFAULT_FORWARD_REQUEST_TIMEOUT = TimeUnit.SECONDS.toMillis(15L);
-
- public static final Set<ClientChannelEvent> STATIC_IO_MSG_RECEIVED_EVENTS =
- Collections.unmodifiableSet(EnumSet.of(ClientChannelEvent.OPENED, ClientChannelEvent.CLOSED));
-
- private final ConnectionService service;
- private final IoHandlerFactory socksProxyIoHandlerFactory = () -> new SocksProxy(getConnectionService());
- private final Session sessionInstance;
- private final Map<Integer, SshdSocketAddress> localToRemote = new TreeMap<>(Comparator.naturalOrder());
- private final Map<Integer, SshdSocketAddress> remoteToLocal = new TreeMap<>(Comparator.naturalOrder());
- private final Map<Integer, SocksProxy> dynamicLocal = new TreeMap<>(Comparator.naturalOrder());
- private final Set<LocalForwardingEntry> localForwards = new HashSet<>();
- private final IoHandlerFactory staticIoHandlerFactory = StaticIoHandler::new;
- private final Collection<PortForwardingEventListener> listeners = new CopyOnWriteArraySet<>();
- private final Collection<PortForwardingEventListenerManager> managersHolder = new CopyOnWriteArraySet<>();
- private final PortForwardingEventListener listenerProxy;
-
- private IoAcceptor acceptor;
-
- public DefaultTcpipForwarder(ConnectionService service) {
- this.service = Objects.requireNonNull(service, "No connection service");
- this.sessionInstance = Objects.requireNonNull(service.getSession(), "No session");
- this.listenerProxy = EventListenerUtils.proxyWrapper(PortForwardingEventListener.class, getClass().getClassLoader(), listeners);
- }
-
- @Override
- public PortForwardingEventListener getPortForwardingEventListenerProxy() {
- return listenerProxy;
- }
-
- @Override
- public void addPortForwardingEventListener(PortForwardingEventListener listener) {
- listeners.add(PortForwardingEventListener.validateListener(listener));
- }
-
- @Override
- public void removePortForwardingEventListener(PortForwardingEventListener listener) {
- if (listener == null) {
- return;
- }
-
- listeners.remove(PortForwardingEventListener.validateListener(listener));
- }
-
- @Override
- public Collection<PortForwardingEventListenerManager> getRegisteredManagers() {
- return managersHolder.isEmpty() ? Collections.emptyList() : new ArrayList<>(managersHolder);
- }
-
- @Override
- public boolean addPortForwardingEventListenerManager(PortForwardingEventListenerManager manager) {
- return managersHolder.add(Objects.requireNonNull(manager, "No manager"));
- }
-
- @Override
- public boolean removePortForwardingEventListenerManager(PortForwardingEventListenerManager manager) {
- if (manager == null) {
- return false;
- }
-
- return managersHolder.remove(manager);
- }
-
- @Override
- public Session getSession() {
- return sessionInstance;
- }
-
- public final ConnectionService getConnectionService() {
- return service;
- }
-
- protected Collection<PortForwardingEventListener> getDefaultListeners() {
- Collection<PortForwardingEventListener> defaultListeners = new ArrayList<>();
- defaultListeners.add(getPortForwardingEventListenerProxy());
-
- Session session = getSession();
- PortForwardingEventListener l = session.getPortForwardingEventListenerProxy();
- if (l != null) {
- defaultListeners.add(l);
- }
-
- FactoryManager manager = (session == null) ? null : session.getFactoryManager();
- l = (manager == null) ? null : manager.getPortForwardingEventListenerProxy();
- if (l != null) {
- defaultListeners.add(l);
- }
-
- return defaultListeners;
- }
-
- //
- // TcpIpForwarder implementation
- //
-
- @Override
- public synchronized SshdSocketAddress startLocalPortForwarding(SshdSocketAddress local, SshdSocketAddress remote) throws IOException {
- Objects.requireNonNull(local, "Local address is null");
- ValidateUtils.checkTrue(local.getPort() >= 0, "Invalid local port: %s", local);
- Objects.requireNonNull(remote, "Remote address is null");
-
- if (isClosed()) {
- throw new IllegalStateException("TcpipForwarder is closed");
- }
- if (isClosing()) {
- throw new IllegalStateException("TcpipForwarder is closing");
- }
-
- InetSocketAddress bound;
- int port;
- signalEstablishingExplicitTunnel(local, remote, true);
- try {
- bound = doBind(local, staticIoHandlerFactory);
- port = bound.getPort();
- SshdSocketAddress prev;
- synchronized (localToRemote) {
- prev = localToRemote.put(port, remote);
- }
-
- if (prev != null) {
- throw new IOException("Multiple local port forwarding bindings on port=" + port + ": current=" + remote + ", previous=" + prev);
- }
- } catch (IOException | RuntimeException e) {
- try {
- stopLocalPortForwarding(local);
- } catch (IOException | RuntimeException err) {
- e.addSuppressed(err);
- }
- signalEstablishedExplicitTunnel(local, remote, true, null, e);
- throw e;
- }
-
- try {
- SshdSocketAddress result = new SshdSocketAddress(bound.getHostString(), port);
- if (log.isDebugEnabled()) {
- log.debug("startLocalPortForwarding(" + local + " -> " + remote + "): " + result);
- }
- signalEstablishedExplicitTunnel(local, remote, true, result, null);
- return result;
- } catch (IOException | RuntimeException e) {
- stopLocalPortForwarding(local);
- throw e;
- }
- }
-
- @Override
- public synchronized void stopLocalPortForwarding(SshdSocketAddress local) throws IOException {
- Objects.requireNonNull(local, "Local address is null");
-
- SshdSocketAddress bound;
- synchronized (localToRemote) {
- bound = localToRemote.remove(local.getPort());
- }
-
- if ((bound != null) && (acceptor != null)) {
- if (log.isDebugEnabled()) {
- log.debug("stopLocalPortForwarding(" + local + ") unbind " + bound);
- }
-
- signalTearingDownExplicitTunnel(bound, true);
- try {
- acceptor.unbind(bound.toInetSocketAddress());
- } catch (RuntimeException e) {
- signalTornDownExplicitTunnel(bound, true, e);
- throw e;
- }
-
- signalTornDownExplicitTunnel(bound, true, null);
- } else {
- if (log.isDebugEnabled()) {
- log.debug("stopLocalPortForwarding(" + local + ") no mapping/acceptor for " + bound);
- }
- }
- }
-
- @Override
- public synchronized SshdSocketAddress startRemotePortForwarding(SshdSocketAddress remote, SshdSocketAddress local) throws IOException {
- Objects.requireNonNull(local, "Local address is null");
- Objects.requireNonNull(remote, "Remote address is null");
-
- String remoteHost = remote.getHostName();
- int remotePort = remote.getPort();
- Session session = getSession();
- Buffer buffer = session.createBuffer(SshConstants.SSH_MSG_GLOBAL_REQUEST, remoteHost.length() + Long.SIZE);
- buffer.putString("tcpip-forward");
- buffer.putBoolean(true); // want reply
- buffer.putString(remoteHost);
- buffer.putInt(remotePort);
-
- long timeout = session.getLongProperty(FORWARD_REQUEST_TIMEOUT, DEFAULT_FORWARD_REQUEST_TIMEOUT);
- Buffer result;
- int port;
- signalEstablishingExplicitTunnel(local, remote, false);
- try {
- result = session.request("tcpip-forward", buffer, timeout, TimeUnit.MILLISECONDS);
- if (result == null) {
- throw new SshException("Tcpip forwarding request denied by server");
- }
- port = (remotePort == 0) ? result.getInt() : remote.getPort();
- // TODO: Is it really safe to only store the local address after the request ?
- SshdSocketAddress prev;
- synchronized (remoteToLocal) {
- prev = remoteToLocal.put(port, local);
- }
-
- if (prev != null) {
- throw new IOException("Multiple remote port forwarding bindings on port=" + port + ": current=" + remote + ", previous=" + prev);
- }
- } catch (IOException | RuntimeException e) {
- try {
- stopRemotePortForwarding(remote);
- } catch (IOException | RuntimeException err) {
- e.addSuppressed(err);
- }
- signalEstablishedExplicitTunnel(local, remote, false, null, e);
- throw e;
- }
-
- try {
- SshdSocketAddress bound = new SshdSocketAddress(remoteHost, port);
- if (log.isDebugEnabled()) {
- log.debug("startRemotePortForwarding(" + remote + " -> " + local + "): " + bound);
- }
-
- signalEstablishedExplicitTunnel(local, remote, false, bound, null);
- return bound;
- } catch (IOException | RuntimeException e) {
- stopRemotePortForwarding(remote);
- throw e;
- }
- }
-
- @Override
- public synchronized void stopRemotePortForwarding(SshdSocketAddress remote) throws IOException {
- SshdSocketAddress bound;
- synchronized (remoteToLocal) {
- bound = remoteToLocal.remove(remote.getPort());
- }
-
- if (bound != null) {
- if (log.isDebugEnabled()) {
- log.debug("stopRemotePortForwarding(" + remote + ") cancel forwarding to " + bound);
- }
-
- String remoteHost = remote.getHostName();
- Session session = getSession();
- Buffer buffer = session.createBuffer(SshConstants.SSH_MSG_GLOBAL_REQUEST, remoteHost.length() + Long.SIZE);
- buffer.putString("cancel-tcpip-forward");
- buffer.putBoolean(false); // want reply
- buffer.putString(remoteHost);
- buffer.putInt(remote.getPort());
-
- signalTearingDownExplicitTunnel(bound, false);
- try {
- session.writePacket(buffer);
- } catch (IOException | RuntimeException e) {
- signalTornDownExplicitTunnel(bound, false, e);
- throw e;
- }
-
- signalTornDownExplicitTunnel(bound, false, null);
- } else {
- if (log.isDebugEnabled()) {
- log.debug("stopRemotePortForwarding(" + remote + ") no binding found");
- }
- }
- }
-
- protected void signalTearingDownExplicitTunnel(SshdSocketAddress boundAddress, boolean localForwarding) throws IOException {
- try {
- invokePortEventListenerSignaller(l -> {
- signalTearingDownExplicitTunnel(l, boundAddress, localForwarding);
- return null;
- });
- } catch (Throwable t) {
- if (t instanceof RuntimeException) {
- throw (RuntimeException) t;
- } else if (t instanceof Error) {
- throw (Error) t;
- } else if (t instanceof IOException) {
- throw (IOException) t;
- } else {
- throw new IOException("Failed (" + t.getClass().getSimpleName() + ")"
- + " to signal tearing down explicit tunnel for local=" + localForwarding
- + " on bound=" + boundAddress, t);
- }
- }
- }
-
- protected void signalTearingDownExplicitTunnel(
- PortForwardingEventListener listener, SshdSocketAddress boundAddress, boolean localForwarding)
- throws IOException {
- if (listener == null) {
- return;
- }
-
- listener.tearingDownExplicitTunnel(getSession(), boundAddress, localForwarding);
- }
-
- protected void signalTornDownExplicitTunnel(SshdSocketAddress boundAddress, boolean localForwarding, Throwable reason) throws IOException {
- try {
- invokePortEventListenerSignaller(l -> {
- signalTornDownExplicitTunnel(l, boundAddress, localForwarding, reason);
- return null;
- });
- } catch (Throwable t) {
- if (t instanceof RuntimeException) {
- throw (RuntimeException) t;
- } else if (t instanceof Error) {
- throw (Error) t;
- } else if (t instanceof IOException) {
- throw (IOException) t;
- } else {
- throw new IOException("Failed (" + t.getClass().getSimpleName() + ")"
- + " to signal torn down explicit tunnel local=" + localForwarding
- + " on bound=" + boundAddress, t);
- }
- }
- }
-
- protected void signalTornDownExplicitTunnel(
- PortForwardingEventListener listener, SshdSocketAddress boundAddress, boolean localForwarding, Throwable reason)
- throws IOException {
- if (listener == null) {
- return;
- }
-
- listener.tornDownExplicitTunnel(getSession(), boundAddress, localForwarding, reason);
- }
-
- @Override
- public synchronized SshdSocketAddress startDynamicPortForwarding(SshdSocketAddress local) throws IOException {
- Objects.requireNonNull(local, "Local address is null");
- ValidateUtils.checkTrue(local.getPort() >= 0, "Invalid local port: %s", local);
-
- if (isClosed()) {
- throw new IllegalStateException("TcpipForwarder is closed");
- }
- if (isClosing()) {
- throw new IllegalStateException("TcpipForwarder is closing");
- }
-
- SocksProxy socksProxy = new SocksProxy(service);
- SocksProxy prev;
- InetSocketAddress bound;
- int port;
- signalEstablishingDynamicTunnel(local);
- try {
- bound = doBind(local, socksProxyIoHandlerFactory);
- port = bound.getPort();
- synchronized (dynamicLocal) {
- prev = dynamicLocal.put(port, socksProxy);
- }
-
- if (prev != null) {
- throw new IOException("Multiple dynamic port mappings found for port=" + port + ": current=" + socksProxy + ", previous=" + prev);
- }
- } catch (IOException | RuntimeException e) {
- try {
- stopDynamicPortForwarding(local);
- } catch (IOException | RuntimeException err) {
- e.addSuppressed(err);
- }
- signalEstablishedDynamicTunnel(local, null, e);
- throw e;
- }
-
- try {
- SshdSocketAddress result = new SshdSocketAddress(bound.getHostString(), port);
- if (log.isDebugEnabled()) {
- log.debug("startDynamicPortForwarding(" + local + "): " + result);
- }
-
- signalEstablishedDynamicTunnel(local, result, null);
- return result;
- } catch (IOException | RuntimeException e) {
- stopDynamicPortForwarding(local);
- throw e;
- }
- }
-
- protected void signalEstablishedDynamicTunnel(
- SshdSocketAddress local, SshdSocketAddress boundAddress, Throwable reason)
- throws IOException {
- try {
- invokePortEventListenerSignaller(l -> {
- signalEstablishedDynamicTunnel(l, local, boundAddress, reason);
- return null;
- });
- } catch (Throwable t) {
- if (t instanceof RuntimeException) {
- throw (RuntimeException) t;
- } else if (t instanceof Error) {
- throw (Error) t;
- } else if (t instanceof IOException) {
- throw (IOException) t;
- } else {
- throw new IOException("Failed (" + t.getClass().getSimpleName() + ")"
- + " to signal establishing dynamic tunnel for local=" + local
- + " on bound=" + boundAddress, t);
- }
- }
- }
-
- protected void signalEstablishedDynamicTunnel(PortForwardingEventListener listener,
- SshdSocketAddress local, SshdSocketAddress boundAddress, Throwable reason)
- throws IOException {
- if (listener == null) {
- return;
- }
-
- listener.establishedDynamicTunnel(getSession(), local, boundAddress, reason);
- }
-
- protected void signalEstablishingDynamicTunnel(SshdSocketAddress local) throws IOException {
- try {
- invokePortEventListenerSignaller(l -> {
- signalEstablishingDynamicTunnel(l, local);
- return null;
- });
- } catch (Throwable t) {
- if (t instanceof RuntimeException) {
- throw (RuntimeException) t;
- } else if (t instanceof Error) {
- throw (Error) t;
- } else if (t instanceof IOException) {
- throw (IOException) t;
- } else {
- throw new IOException("Failed (" + t.getClass().getSimpleName() + ")"
- + " to signal establishing dynamic tunnel for local=" + local, t);
- }
- }
- }
-
- protected void signalEstablishingDynamicTunnel(PortForwardingEventListener listener, SshdSocketAddress local) throws IOException {
- if (listener == null) {
- return;
- }
-
- listener.establishingDynamicTunnel(getSession(), local);
- }
-
- @Override
- public synchronized void stopDynamicPortForwarding(SshdSocketAddress local) throws IOException {
- SocksProxy obj;
- synchronized (dynamicLocal) {
- obj = dynamicLocal.remove(local.getPort());
- }
-
- if (obj != null) {
- if (log.isDebugEnabled()) {
- log.debug("stopDynamicPortForwarding(" + local + ") unbinding");
- }
-
- signalTearingDownDynamicTunnel(local);
- try {
- obj.close(true);
- acceptor.unbind(local.toInetSocketAddress());
- } catch (RuntimeException e) {
- signalTornDownDynamicTunnel(local, e);
- throw e;
- }
-
- signalTornDownDynamicTunnel(local, null);
- } else {
- if (log.isDebugEnabled()) {
- log.debug("stopDynamicPortForwarding(" + local + ") no binding found");
- }
- }
- }
-
- protected void signalTearingDownDynamicTunnel(SshdSocketAddress address) throws IOException {
- try {
- invokePortEventListenerSignaller(l -> {
- signalTearingDownDynamicTunnel(l, address);
- return null;
- });
- } catch (Throwable t) {
- if (t instanceof RuntimeException) {
- throw (RuntimeException) t;
- } else if (t instanceof Error) {
- throw (Error) t;
- } else if (t instanceof IOException) {
- throw (IOException) t;
- } else {
- throw new IOException("Failed (" + t.getClass().getSimpleName() + ")"
- + " to signal tearing down dynamic tunnel for address=" + address, t);
- }
- }
- }
-
- protected void signalTearingDownDynamicTunnel(PortForwardingEventListener listener, SshdSocketAddress address) throws IOException {
- if (listener == null) {
- return;
- }
-
- listener.tearingDownDynamicTunnel(getSession(), address);
- }
-
- protected void signalTornDownDynamicTunnel(SshdSocketAddress address, Throwable reason) throws IOException {
- try {
- invokePortEventListenerSignaller(l -> {
- signalTornDownDynamicTunnel(l, address, reason);
- return null;
- });
- } catch (Throwable t) {
- if (t instanceof RuntimeException) {
- throw (RuntimeException) t;
- } else if (t instanceof Error) {
- throw (Error) t;
- } else if (t instanceof IOException) {
- throw (IOException) t;
- } else {
- throw new IOException("Failed (" + t.getClass().getSimpleName() + ")"
- + " to signal torn down dynamic tunnel for address=" + address, t);
- }
- }
- }
-
- protected void signalTornDownDynamicTunnel(
- PortForwardingEventListener listener, SshdSocketAddress address, Throwable reason)
- throws IOException {
- if (listener == null) {
- return;
- }
-
- listener.tornDownDynamicTunnel(getSession(), address, reason);
- }
-
- @Override
- public synchronized SshdSocketAddress getForwardedPort(int remotePort) {
- synchronized (remoteToLocal) {
- return remoteToLocal.get(remotePort);
- }
- }
-
- @Override
- public synchronized SshdSocketAddress localPortForwardingRequested(SshdSocketAddress local) throws IOException {
- Objects.requireNonNull(local, "Local address is null");
- ValidateUtils.checkTrue(local.getPort() >= 0, "Invalid local port: %s", local);
-
- Session session = getSession();
- FactoryManager manager = Objects.requireNonNull(session.getFactoryManager(), "No factory manager");
- ForwardingFilter filter = manager.getTcpipForwardingFilter();
- try {
- if ((filter == null) || (!filter.canListen(local, session))) {
- if (log.isDebugEnabled()) {
- log.debug("localPortForwardingRequested(" + session + ")[" + local + "][haveFilter=" + (filter != null) + "] rejected");
- }
- return null;
- }
- } catch (Error e) {
- log.warn("localPortForwardingRequested({})[{}] failed ({}) to consult forwarding filter: {}",
- session, local, e.getClass().getSimpleName(), e.getMessage());
- if (log.isDebugEnabled()) {
- log.debug("localPortForwardingRequested(" + this + ")[" + local + "] filter consultation failure details", e);
- }
- throw new RuntimeSshException(e);
- }
-
- signalEstablishingExplicitTunnel(local, null, true);
- SshdSocketAddress result;
- try {
- InetSocketAddress bound = doBind(local, staticIoHandlerFactory);
- result = new SshdSocketAddress(bound.getHostString(), bound.getPort());
- if (log.isDebugEnabled()) {
- log.debug("localPortForwardingRequested(" + local + "): " + result);
- }
-
- boolean added;
- synchronized (localForwards) {
- // NOTE !!! it is crucial to use the bound address host name first
- added = localForwards.add(new LocalForwardingEntry(result.getHostName(), local.getHostName(), result.getPort()));
- }
-
- if (!added) {
- throw new IOException("Failed to add local port forwarding entry for " + local + " -> " + result);
- }
- } catch (IOException | RuntimeException e) {
- try {
- localPortForwardingCancelled(local);
- } catch (IOException | RuntimeException err) {
- e.addSuppressed(e);
- }
- signalEstablishedExplicitTunnel(local, null, true, null, e);
- throw e;
- }
-
- try {
- signalEstablishedExplicitTunnel(local, null, true, result, null);
- return result;
- } catch (IOException | RuntimeException e) {
- throw e;
- }
- }
-
- @Override
- public synchronized void localPortForwardingCancelled(SshdSocketAddress local) throws IOException {
- LocalForwardingEntry entry;
- synchronized (localForwards) {
- entry = LocalForwardingEntry.findMatchingEntry(local.getHostName(), local.getPort(), localForwards);
- if (entry != null) {
- localForwards.remove(entry);
- }
- }
-
- if ((entry != null) && (acceptor != null)) {
- if (log.isDebugEnabled()) {
- log.debug("localPortForwardingCancelled(" + local + ") unbind " + entry);
- }
-
- signalTearingDownExplicitTunnel(entry, true);
- try {
- acceptor.unbind(entry.toInetSocketAddress());
- } catch (RuntimeException e) {
- signalTornDownExplicitTunnel(entry, true, e);
- throw e;
- }
-
- signalTornDownExplicitTunnel(entry, true, null);
- } else {
- if (log.isDebugEnabled()) {
- log.debug("localPortForwardingCancelled(" + local + ") no match/acceptor: " + entry);
- }
- }
- }
-
- protected void signalEstablishingExplicitTunnel(
- SshdSocketAddress local, SshdSocketAddress remote, boolean localForwarding)
- throws IOException {
- try {
- invokePortEventListenerSignaller(l -> {
- signalEstablishingExplicitTunnel(l, local, remote, localForwarding);
- return null;
- });
- } catch (Throwable t) {
- if (t instanceof RuntimeException) {
- throw (RuntimeException) t;
- } else if (t instanceof Error) {
- throw (Error) t;
- } else if (t instanceof IOException) {
- throw (IOException) t;
- } else {
- throw new IOException("Failed (" + t.getClass().getSimpleName() + ")"
- + " to signal establishing explicit tunnel for local=" + local
- + ", remote=" + remote + ", localForwarding=" + localForwarding, t);
- }
- }
- }
-
- protected void signalEstablishingExplicitTunnel(PortForwardingEventListener listener,
- SshdSocketAddress local, SshdSocketAddress remote, boolean localForwarding)
- throws IOException {
- if (listener == null) {
- return;
- }
-
- listener.establishingExplicitTunnel(getSession(), local, remote, localForwarding);
- }
-
- protected void signalEstablishedExplicitTunnel(
- SshdSocketAddress local, SshdSocketAddress remote, boolean localForwarding,
- SshdSocketAddress boundAddress, Throwable reason)
- throws IOException {
- try {
- invokePortEventListenerSignaller(l -> {
- signalEstablishedExplicitTunnel(l, local, remote, localForwarding, boundAddress, reason);
- return null;
- });
- } catch (Throwable t) {
- if (t instanceof RuntimeException) {
- throw (RuntimeException) t;
- } else if (t instanceof Error) {
- throw (Error) t;
- } else if (t instanceof IOException) {
- throw (IOException) t;
- } else {
- throw new IOException("Failed (" + t.getClass().getSimpleName() + ")"
- + " to signal established explicit tunnel for local=" + local
- + ", remote=" + remote + ", localForwarding=" + localForwarding
- + ", bound=" + boundAddress, t);
- }
- }
- }
-
- protected void signalEstablishedExplicitTunnel(PortForwardingEventListener listener,
- SshdSocketAddress local, SshdSocketAddress remote, boolean localForwarding,
- SshdSocketAddress boundAddress, Throwable reason)
- throws IOException {
- if (listener == null) {
- return;
- }
-
- listener.establishedExplicitTunnel(getSession(), local, remote, localForwarding, boundAddress, reason);
- }
-
- protected void invokePortEventListenerSignaller(Invoker<PortForwardingEventListener, Void> invoker) throws Throwable {
- Throwable err = null;
- try {
- invokePortEventListenerSignallerListeners(getDefaultListeners(), invoker);
- } catch (Throwable t) {
- Throwable e = GenericUtils.peelException(t);
- err = GenericUtils.accumulateException(err, e);
- }
-
- try {
- invokePortEventListenerSignallerHolders(managersHolder, invoker);
- } catch (Throwable t) {
- Throwable e = GenericUtils.peelException(t);
- err = GenericUtils.accumulateException(err, e);
- }
-
-
- if (err != null) {
- throw err;
- }
- }
-
- protected void invokePortEventListenerSignallerListeners(
- Collection<? extends PortForwardingEventListener> listeners, Invoker<PortForwardingEventListener, Void> invoker)
- throws Throwable {
- if (GenericUtils.isEmpty(listeners)) {
- return;
- }
-
- Throwable err = null;
- // Need to go over the hierarchy (session, factory managed, connection service, etc...)
- for (PortForwardingEventListener l : listeners) {
- if (l == null) {
- continue;
- }
-
- try {
- invoker.invoke(l);
- } catch (Throwable t) {
- Throwable e = GenericUtils.peelException(t);
- err = GenericUtils.accumulateException(err, e);
- }
- }
-
- if (err != null) {
- throw err;
- }
- }
-
- protected void invokePortEventListenerSignallerHolders(
- Collection<? extends PortForwardingEventListenerManager> holders, Invoker<PortForwardingEventListener, Void> invoker)
- throws Throwable {
- if (GenericUtils.isEmpty(holders)) {
- return;
- }
-
- Throwable err = null;
- // Need to go over the hierarchy (session, factory managed, connection service, etc...)
- for (PortForwardingEventListenerManager m : holders) {
- try {
- PortForwardingEventListener listener = m.getPortForwardingEventListenerProxy();
- if (listener != null) {
- invoker.invoke(listener);
- }
- } catch (Throwable t) {
- Throwable e = GenericUtils.peelException(t);
- err = GenericUtils.accumulateException(err, e);
- }
-
- if (m instanceof PortForwardingEventListenerManagerHolder) {
- try {
- invokePortEventListenerSignallerHolders(((PortForwardingEventListenerManagerHolder) m).getRegisteredManagers(), invoker);
- } catch (Throwable t) {
- Throwable e = GenericUtils.peelException(t);
- err = GenericUtils.accumulateException(err, e);
- }
- }
- }
-
- if (err != null) {
- throw err;
- }
- }
-
- @Override
- protected synchronized Closeable getInnerCloseable() {
- return builder().parallel(dynamicLocal.values()).close(acceptor).build();
- }
-
- @Override
- protected void preClose() {
- this.listeners.clear();
- this.managersHolder.clear();
- super.preClose();
- }
-
- /**
- * @param address The request bind address
- * @param handlerFactory A {@link Factory} to create an {@link IoHandler} if necessary
- * @return The {@link InetSocketAddress} to which the binding occurred
- * @throws IOException If failed to bind
- */
- private InetSocketAddress doBind(SshdSocketAddress address, Factory<? extends IoHandler> handlerFactory) throws IOException {
- if (acceptor == null) {
- Session session = getSession();
- FactoryManager manager = Objects.requireNonNull(session.getFactoryManager(), "No factory manager");
- IoServiceFactory factory = Objects.requireNonNull(manager.getIoServiceFactory(), "No I/O service factory");
- IoHandler handler = handlerFactory.create();
- acceptor = factory.createAcceptor(handler);
- }
-
- // TODO find a better way to determine the resulting bind address - what if multi-threaded calls...
- Set<SocketAddress> before = acceptor.getBoundAddresses();
- try {
- InetSocketAddress bindAddress = address.toInetSocketAddress();
- acceptor.bind(bindAddress);
-
- Set<SocketAddress> after = acceptor.getBoundAddresses();
- if (GenericUtils.size(after) > 0) {
- after.removeAll(before);
- }
- if (GenericUtils.isEmpty(after)) {
- throw new IOException("Error binding to " + address + "[" + bindAddress + "]: no local addresses bound");
- }
-
- if (after.size() > 1) {
- throw new IOException("Multiple local addresses have been bound for " + address + "[" + bindAddress + "]");
- }
- return (InetSocketAddress) after.iterator().next();
- } catch (IOException bindErr) {
- Set<SocketAddress> after = acceptor.getBoundAddresses();
- if (GenericUtils.isEmpty(after)) {
- close();
- }
- throw bindErr;
- }
- }
-
- @Override
- public String toString() {
- return getClass().getSimpleName() + "[" + getSession() + "]";
- }
-
- //
- // Static IoHandler implementation
- //
-
- class StaticIoHandler implements IoHandler {
- StaticIoHandler() {
- super();
- }
-
- @Override
- @SuppressWarnings("synthetic-access")
- public void sessionCreated(final IoSession session) throws Exception {
- InetSocketAddress local = (InetSocketAddress) session.getLocalAddress();
- int localPort = local.getPort();
- SshdSocketAddress remote = localToRemote.get(localPort);
- if (log.isDebugEnabled()) {
- log.debug("sessionCreated({}) remote={}", session, remote);
- }
-
- final TcpipClientChannel channel;
- if (remote != null) {
- 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(future -> {
- Throwable t = future.getException();
- if (t != null) {
- log.warn("Failed ({}) to open channel for session={}: {}",
- t.getClass().getSimpleName(), session, t.getMessage());
- if (log.isDebugEnabled()) {
- log.debug("sessionCreated(" + session + ") channel=" + channel + " open failure details", t);
- }
- DefaultTcpipForwarder.this.service.unregisterChannel(channel);
- channel.close(false);
- }
- });
- }
-
- @Override
- @SuppressWarnings("synthetic-access")
- public void sessionClosed(IoSession session) throws Exception {
- TcpipClientChannel channel = (TcpipClientChannel) session.getAttribute(TcpipClientChannel.class);
- if (channel != null) {
- if (log.isDebugEnabled()) {
- log.debug("sessionClosed({}) closing channel={}", session, channel);
- }
- channel.close(false);
- }
- }
-
- @Override
- @SuppressWarnings("synthetic-access")
- public void messageReceived(IoSession session, Readable message) throws Exception {
- TcpipClientChannel channel = (TcpipClientChannel) session.getAttribute(TcpipClientChannel.class);
- Buffer buffer = new ByteArrayBuffer(message.available() + Long.SIZE, false);
- buffer.putBuffer(message);
-
- Collection<ClientChannelEvent> result = channel.waitFor(STATIC_IO_MSG_RECEIVED_EVENTS, Long.MAX_VALUE);
- if (log.isTraceEnabled()) {
- log.trace("messageReceived({}) channel={}, len={} wait result: {}",
- session, channel, result, buffer.array());
- }
-
- OutputStream outputStream = channel.getInvertedIn();
- outputStream.write(buffer.array(), buffer.rpos(), buffer.available());
- outputStream.flush();
- }
-
- @Override
- @SuppressWarnings("synthetic-access")
- public void exceptionCaught(IoSession session, Throwable cause) throws Exception {
- if (log.isDebugEnabled()) {
- log.debug("exceptionCaught({}) {}: {}", session, cause.getClass().getSimpleName(), cause.getMessage());
- }
- if (log.isTraceEnabled()) {
- log.trace("exceptionCaught(" + session + ") caught exception details", cause);
- }
- session.close(false);
- }
- }
-}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/aa551bc0/sshd-core/src/main/java/org/apache/sshd/common/forward/DefaultTcpipForwarderFactory.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/forward/DefaultTcpipForwarderFactory.java b/sshd-core/src/main/java/org/apache/sshd/common/forward/DefaultTcpipForwarderFactory.java
deleted file mode 100644
index 808f41d..0000000
--- a/sshd-core/src/main/java/org/apache/sshd/common/forward/DefaultTcpipForwarderFactory.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * 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.util.Collection;
-import java.util.concurrent.CopyOnWriteArraySet;
-
-import org.apache.sshd.common.session.ConnectionService;
-import org.apache.sshd.common.util.EventListenerUtils;
-
-/**
- * The default {@link TcpipForwarderFactory} implementation.
- *
- * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
- */
-public class DefaultTcpipForwarderFactory implements TcpipForwarderFactory, PortForwardingEventListenerManager {
- public static final DefaultTcpipForwarderFactory INSTANCE = new DefaultTcpipForwarderFactory() {
- @Override
- public void addPortForwardingEventListener(PortForwardingEventListener listener) {
- throw new UnsupportedOperationException("addPortForwardingListener(" + listener + ") N/A on default instance");
- }
-
- @Override
- public void removePortForwardingEventListener(PortForwardingEventListener listener) {
- throw new UnsupportedOperationException("removePortForwardingEventListener(" + listener + ") N/A on default instance");
- }
-
- @Override
- public PortForwardingEventListener getPortForwardingEventListenerProxy() {
- return PortForwardingEventListener.EMPTY;
- }
- };
-
- private final Collection<PortForwardingEventListener> listeners = new CopyOnWriteArraySet<>();
- private final PortForwardingEventListener listenerProxy;
-
- public DefaultTcpipForwarderFactory() {
- listenerProxy = EventListenerUtils.proxyWrapper(PortForwardingEventListener.class, getClass().getClassLoader(), listeners);
- }
-
- @Override
- public PortForwardingEventListener getPortForwardingEventListenerProxy() {
- return listenerProxy;
- }
-
- @Override
- public void addPortForwardingEventListener(PortForwardingEventListener listener) {
- listeners.add(PortForwardingEventListener.validateListener(listener));
- }
-
- @Override
- public void removePortForwardingEventListener(PortForwardingEventListener listener) {
- if (listener == null) {
- return;
- }
-
- listeners.remove(PortForwardingEventListener.validateListener(listener));
- }
-
- @Override
- public TcpipForwarder create(ConnectionService service) {
- TcpipForwarder forwarder = new DefaultTcpipForwarder(service);
- forwarder.addPortForwardingEventListenerManager(this);
- return forwarder;
- }
-}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/aa551bc0/sshd-core/src/main/java/org/apache/sshd/common/forward/ForwardingFilter.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/forward/ForwardingFilter.java b/sshd-core/src/main/java/org/apache/sshd/common/forward/ForwardingFilter.java
new file mode 100644
index 0000000..5c3583b
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/common/forward/ForwardingFilter.java
@@ -0,0 +1,59 @@
+/*
+ * 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 org.apache.sshd.common.Closeable;
+import org.apache.sshd.common.util.net.SshdSocketAddress;
+
+/**
+ * TODO Add javadoc
+ *
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public interface ForwardingFilter
+ extends PortForwardingManager,
+ PortForwardingEventListenerManager,
+ PortForwardingEventListenerManagerHolder,
+ Closeable {
+ /**
+ * @param remotePort The remote port
+ * @return The local {@link SshdSocketAddress} that the remote port is forwarded to
+ */
+ SshdSocketAddress getForwardedPort(int remotePort);
+
+ /**
+ * Called when the other side requested a remote port forward.
+ *
+ * @param local The request address
+ * @return The bound local {@link SshdSocketAddress} - {@code null} if not allowed to forward
+ * @throws IOException If failed to handle request
+ */
+ SshdSocketAddress localPortForwardingRequested(SshdSocketAddress local) throws IOException;
+
+ /**
+ * Called when the other side cancelled a remote port forward.
+ *
+ * @param local The local {@link SshdSocketAddress}
+ * @throws IOException If failed to handle request
+ */
+ void localPortForwardingCancelled(SshdSocketAddress local) throws IOException;
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/aa551bc0/sshd-core/src/main/java/org/apache/sshd/common/forward/ForwardingFilterFactory.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/forward/ForwardingFilterFactory.java b/sshd-core/src/main/java/org/apache/sshd/common/forward/ForwardingFilterFactory.java
new file mode 100644
index 0000000..485cbe7
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/common/forward/ForwardingFilterFactory.java
@@ -0,0 +1,37 @@
+/*
+ * 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 org.apache.sshd.common.session.ConnectionService;
+
+/**
+ * A factory for creating forwarder objects for client port forwarding
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+@FunctionalInterface
+public interface ForwardingFilterFactory {
+
+ /**
+ * Creates the forwarder to be used for TCP/IP port forwards for this session.
+ *
+ * @param service the {@link ConnectionService} the connections are forwarded through
+ * @return the {@link ForwardingFilter} that will listen for connections and set up forwarding
+ */
+ ForwardingFilter create(ConnectionService service);
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/aa551bc0/sshd-core/src/main/java/org/apache/sshd/common/forward/TcpipForwarder.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/forward/TcpipForwarder.java b/sshd-core/src/main/java/org/apache/sshd/common/forward/TcpipForwarder.java
deleted file mode 100644
index 5e3d9ce..0000000
--- a/sshd-core/src/main/java/org/apache/sshd/common/forward/TcpipForwarder.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * 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 org.apache.sshd.common.Closeable;
-import org.apache.sshd.common.util.net.SshdSocketAddress;
-
-public interface TcpipForwarder
- extends PortForwardingManager,
- PortForwardingEventListenerManager,
- PortForwardingEventListenerManagerHolder,
- Closeable {
- /**
- * @param remotePort The remote port
- * @return The local {@link SshdSocketAddress} that the remote port is forwarded to
- */
- SshdSocketAddress getForwardedPort(int remotePort);
-
- /**
- * Called when the other side requested a remote port forward.
- *
- * @param local The request address
- * @return The bound local {@link SshdSocketAddress} - {@code null} if not allowed to forward
- * @throws IOException If failed to handle request
- */
- SshdSocketAddress localPortForwardingRequested(SshdSocketAddress local) throws IOException;
-
- /**
- * Called when the other side cancelled a remote port forward.
- *
- * @param local The local {@link SshdSocketAddress}
- * @throws IOException If failed to handle request
- */
- void localPortForwardingCancelled(SshdSocketAddress local) throws IOException;
-}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/aa551bc0/sshd-core/src/main/java/org/apache/sshd/common/forward/TcpipForwarderFactory.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/forward/TcpipForwarderFactory.java b/sshd-core/src/main/java/org/apache/sshd/common/forward/TcpipForwarderFactory.java
deleted file mode 100644
index e001ab2..0000000
--- a/sshd-core/src/main/java/org/apache/sshd/common/forward/TcpipForwarderFactory.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * 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 org.apache.sshd.common.session.ConnectionService;
-
-/**
- * A factory for creating forwarder objects for client port forwarding
- * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
- */
-@FunctionalInterface
-public interface TcpipForwarderFactory {
-
- /**
- * Creates the forwarder to be used for TCP/IP port forwards for this session.
- *
- * @param service the {@link ConnectionService} the connections are forwarded through
- * @return the {@link TcpipForwarder} that will listen for connections and set up forwarding
- */
- TcpipForwarder create(ConnectionService service);
-}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/aa551bc0/sshd-core/src/main/java/org/apache/sshd/common/helpers/AbstractFactoryManager.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/helpers/AbstractFactoryManager.java b/sshd-core/src/main/java/org/apache/sshd/common/helpers/AbstractFactoryManager.java
index f4d584e..93175cf 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/helpers/AbstractFactoryManager.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/helpers/AbstractFactoryManager.java
@@ -42,8 +42,8 @@ import org.apache.sshd.common.channel.ChannelListener;
import org.apache.sshd.common.channel.RequestHandler;
import org.apache.sshd.common.config.VersionProperties;
import org.apache.sshd.common.file.FileSystemFactory;
+import org.apache.sshd.common.forward.ForwardingFilterFactory;
import org.apache.sshd.common.forward.PortForwardingEventListener;
-import org.apache.sshd.common.forward.TcpipForwarderFactory;
import org.apache.sshd.common.io.DefaultIoServiceFactoryFactory;
import org.apache.sshd.common.io.IoServiceFactory;
import org.apache.sshd.common.io.IoServiceFactoryFactory;
@@ -70,8 +70,8 @@ public abstract class AbstractFactoryManager extends AbstractKexFactoryManager i
protected SshAgentFactory agentFactory;
protected ScheduledExecutorService executor;
protected boolean shutdownExecutor;
- protected TcpipForwarderFactory tcpipForwarderFactory;
- protected ForwardingFilter tcpipForwardingFilter;
+ protected ForwardingFilterFactory forwarderFactory;
+ protected ForwardingFilter forwardingFilter;
protected FileSystemFactory fileSystemFactory;
protected List<ServiceFactory> serviceFactories;
protected List<RequestHandler<ConnectionService>> globalRequestHandlers;
@@ -217,21 +217,21 @@ public abstract class AbstractFactoryManager extends AbstractKexFactoryManager i
}
@Override
- public TcpipForwarderFactory getTcpipForwarderFactory() {
- return tcpipForwarderFactory;
+ public ForwardingFilterFactory getForwarderFactory() {
+ return forwarderFactory;
}
- public void setTcpipForwarderFactory(TcpipForwarderFactory tcpipForwarderFactory) {
- this.tcpipForwarderFactory = tcpipForwarderFactory;
+ public void setForwarderFactory(ForwardingFilterFactory forwarderFactory) {
+ this.forwarderFactory = forwarderFactory;
}
@Override
- public ForwardingFilter getTcpipForwardingFilter() {
- return tcpipForwardingFilter;
+ public ForwardingFilter getForwardingFilter() {
+ return forwardingFilter;
}
- public void setTcpipForwardingFilter(ForwardingFilter tcpipForwardingFilter) {
- this.tcpipForwardingFilter = tcpipForwardingFilter;
+ public void setForwardingFilter(ForwardingFilter forwardingFilter) {
+ this.forwardingFilter = forwardingFilter;
}
@Override
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/aa551bc0/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 9795e5c..7c4aa22 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
@@ -23,9 +23,9 @@ import java.io.IOException;
import org.apache.sshd.agent.common.AgentForwardSupport;
import org.apache.sshd.common.Service;
import org.apache.sshd.common.channel.Channel;
+import org.apache.sshd.common.forward.ForwardingFilter;
import org.apache.sshd.common.forward.PortForwardingEventListenerManager;
import org.apache.sshd.common.forward.PortForwardingEventListenerManagerHolder;
-import org.apache.sshd.common.forward.TcpipForwarder;
import org.apache.sshd.server.x11.X11ForwardSupport;
/**
@@ -51,11 +51,11 @@ public interface ConnectionService extends Service, PortForwardingEventListenerM
void unregisterChannel(Channel channel);
/**
- * Retrieve the tcpip forwarder
+ * Retrieve the forwarder instance
*
- * @return The {@link TcpipForwarder}
+ * @return The {@link ForwardingFilter}
*/
- TcpipForwarder getTcpipForwarder();
+ ForwardingFilter getForwardingFilter();
// TODO: remove from interface, it's server side only
AgentForwardSupport getAgentForwardSupport();
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/aa551bc0/sshd-core/src/main/java/org/apache/sshd/common/session/helpers/AbstractConnectionService.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/session/helpers/AbstractConnectionService.java b/sshd-core/src/main/java/org/apache/sshd/common/session/helpers/AbstractConnectionService.java
index e3c8ecc..32d0920 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/session/helpers/AbstractConnectionService.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/session/helpers/AbstractConnectionService.java
@@ -45,10 +45,10 @@ import org.apache.sshd.common.channel.Channel;
import org.apache.sshd.common.channel.OpenChannelException;
import org.apache.sshd.common.channel.RequestHandler;
import org.apache.sshd.common.channel.Window;
+import org.apache.sshd.common.forward.ForwardingFilter;
+import org.apache.sshd.common.forward.ForwardingFilterFactory;
import org.apache.sshd.common.forward.PortForwardingEventListener;
import org.apache.sshd.common.forward.PortForwardingEventListenerManager;
-import org.apache.sshd.common.forward.TcpipForwarder;
-import org.apache.sshd.common.forward.TcpipForwarderFactory;
import org.apache.sshd.common.io.AbstractIoWriteFuture;
import org.apache.sshd.common.io.IoWriteFuture;
import org.apache.sshd.common.session.ConnectionService;
@@ -99,7 +99,7 @@ public abstract class AbstractConnectionService<S extends AbstractSession>
private final AtomicReference<AgentForwardSupport> agentForwardHolder = new AtomicReference<>();
private final AtomicReference<X11ForwardSupport> x11ForwardHolder = new AtomicReference<>();
- private final AtomicReference<TcpipForwarder> tcpipForwarderHolder = new AtomicReference<>();
+ private final AtomicReference<ForwardingFilter> forwarderHolder = new AtomicReference<>();
private final AtomicBoolean allowMoreSessions = new AtomicBoolean(true);
private final Collection<PortForwardingEventListener> listeners = new CopyOnWriteArraySet<>();
private final Collection<PortForwardingEventListenerManager> managersHolder = new CopyOnWriteArraySet<>();
@@ -164,21 +164,21 @@ public abstract class AbstractConnectionService<S extends AbstractSession>
}
@Override
- public TcpipForwarder getTcpipForwarder() {
- TcpipForwarder forwarder;
+ public ForwardingFilter getForwardingFilter() {
+ ForwardingFilter forwarder;
S session = getSession();
- synchronized (tcpipForwarderHolder) {
- forwarder = tcpipForwarderHolder.get();
+ synchronized (forwarderHolder) {
+ forwarder = forwarderHolder.get();
if (forwarder != null) {
return forwarder;
}
- forwarder = ValidateUtils.checkNotNull(createTcpipForwarder(session), "No forwarder created for %s", session);
- tcpipForwarderHolder.set(forwarder);
+ forwarder = ValidateUtils.checkNotNull(createForwardingFilter(session), "No forwarder created for %s", session);
+ forwarderHolder.set(forwarder);
}
if (log.isDebugEnabled()) {
- log.debug("getTcpipForwarder({}) created instance", session);
+ log.debug("getForwardingFilter({}) created instance", session);
}
return forwarder;
}
@@ -190,12 +190,12 @@ public abstract class AbstractConnectionService<S extends AbstractSession>
super.preClose();
}
- protected TcpipForwarder createTcpipForwarder(S session) {
+ protected ForwardingFilter createForwardingFilter(S session) {
FactoryManager manager =
- Objects.requireNonNull(session.getFactoryManager(), "No factory manager");
- TcpipForwarderFactory factory =
- Objects.requireNonNull(manager.getTcpipForwarderFactory(), "No forwarder factory");
- TcpipForwarder forwarder = factory.create(this);
+ Objects.requireNonNull(session.getFactoryManager(), "No factory manager");
+ ForwardingFilterFactory factory =
+ Objects.requireNonNull(manager.getForwarderFactory(), "No forwarder factory");
+ ForwardingFilter forwarder = factory.create(this);
forwarder.addPortForwardingEventListenerManager(this);
return forwarder;
}
@@ -252,7 +252,7 @@ public abstract class AbstractConnectionService<S extends AbstractSession>
@Override
protected Closeable getInnerCloseable() {
return builder()
- .sequential(tcpipForwarderHolder.get(), agentForwardHolder.get(), x11ForwardHolder.get())
+ .sequential(forwarderHolder.get(), agentForwardHolder.get(), x11ForwardHolder.get())
.parallel(channels.values())
.build();
}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/aa551bc0/sshd-core/src/main/java/org/apache/sshd/server/SshServer.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/SshServer.java b/sshd-core/src/main/java/org/apache/sshd/server/SshServer.java
index c9f348e..3e7c523 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/SshServer.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/SshServer.java
@@ -44,7 +44,6 @@ import org.apache.sshd.common.Factory;
import org.apache.sshd.common.NamedFactory;
import org.apache.sshd.common.PropertyResolverUtils;
import org.apache.sshd.common.ServiceFactory;
-import org.apache.sshd.common.config.SshConfigFileReader;
import org.apache.sshd.common.config.keys.BuiltinIdentities;
import org.apache.sshd.common.config.keys.KeyUtils;
import org.apache.sshd.common.helpers.AbstractFactoryManager;
@@ -66,7 +65,7 @@ import org.apache.sshd.server.auth.keyboard.KeyboardInteractiveAuthenticator;
import org.apache.sshd.server.auth.password.PasswordAuthenticator;
import org.apache.sshd.server.auth.pubkey.AcceptAllPublickeyAuthenticator;
import org.apache.sshd.server.auth.pubkey.PublickeyAuthenticator;
-import org.apache.sshd.server.forward.AcceptAllForwardingFilter;
+import org.apache.sshd.server.config.SshServerConfigFileReader;
import org.apache.sshd.server.forward.ForwardingFilter;
import org.apache.sshd.server.keyprovider.AbstractGeneratorHostKeyProvider;
import org.apache.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider;
@@ -264,11 +263,6 @@ public class SshServer extends AbstractFactoryManager implements ServerFactoryMa
}
@Override
- public void setTcpipForwardingFilter(ForwardingFilter forwardingFilter) {
- this.tcpipForwardingFilter = forwardingFilter;
- }
-
- @Override
protected void checkConfig() {
super.checkConfig();
@@ -475,14 +469,14 @@ public class SshServer extends AbstractFactoryManager implements ServerFactoryMa
for (int i = 0; i < numArgs; i++) {
String argName = args[i];
if ("-p".equals(argName)) {
- if (i + 1 >= numArgs) {
+ if ((i + 1) >= numArgs) {
System.err.println("option requires an argument: " + argName);
error = true;
break;
}
port = Integer.parseInt(args[++i]);
} else if ("-key-type".equals(argName)) {
- if (i + 1 >= numArgs) {
+ if ((i + 1) >= numArgs) {
System.err.println("option requires an argument: " + argName);
error = true;
break;
@@ -495,7 +489,7 @@ public class SshServer extends AbstractFactoryManager implements ServerFactoryMa
}
hostKeyType = args[++i].toUpperCase();
} else if ("-key-size".equals(argName)) {
- if (i + 1 >= numArgs) {
+ if ((i + 1) >= numArgs) {
System.err.println("option requires an argument: " + argName);
error = true;
break;
@@ -509,7 +503,7 @@ public class SshServer extends AbstractFactoryManager implements ServerFactoryMa
hostKeySize = Integer.parseInt(args[++i]);
} else if ("-key-file".equals(argName)) {
- if (i + 1 >= numArgs) {
+ if ((i + 1) >= numArgs) {
System.err.println("option requires an argument: " + argName);
error = true;
break;
@@ -521,7 +515,7 @@ public class SshServer extends AbstractFactoryManager implements ServerFactoryMa
}
keyFiles.add(keyFilePath);
} else if ("-io".equals(argName)) {
- if (i + 1 >= numArgs) {
+ if ((i + 1) >= numArgs) {
System.err.println("option requires an argument: " + argName);
error = true;
break;
@@ -537,7 +531,7 @@ public class SshServer extends AbstractFactoryManager implements ServerFactoryMa
break;
}
} else if ("-o".equals(argName)) {
- if (i + 1 >= numArgs) {
+ if ((i + 1) >= numArgs) {
System.err.println("option requires and argument: " + argName);
error = true;
break;
@@ -580,7 +574,7 @@ public class SshServer extends AbstractFactoryManager implements ServerFactoryMa
sshd.setShellFactory(InteractiveProcessShellFactory.INSTANCE);
sshd.setPasswordAuthenticator((username, password, session) -> Objects.equals(username, password));
sshd.setPublickeyAuthenticator(AcceptAllPublickeyAuthenticator.INSTANCE);
- sshd.setTcpipForwardingFilter(AcceptAllForwardingFilter.INSTANCE);
+ setupServerForwarding(sshd, options);
sshd.setCommandFactory(new ScpCommandFactory.Builder().withDelegate(
command -> new ProcessShellFactory(GenericUtils.split(command, ' ')).create()
).build());
@@ -590,34 +584,14 @@ public class SshServer extends AbstractFactoryManager implements ServerFactoryMa
Thread.sleep(Long.MAX_VALUE);
}
- public static Object setupServerBanner(ServerFactoryManager server, Map<String, ?> options) throws Exception {
- String bannerOption = GenericUtils.isEmpty(options)
- ? null
- : Objects.toString(options.remove(SshConfigFileReader.BANNER_CONFIG_PROP), null);
- if (GenericUtils.isEmpty(bannerOption)) {
- bannerOption = GenericUtils.isEmpty(options)
- ? null
- : Objects.toString(options.remove(SshConfigFileReader.VISUAL_HOST_KEY), null);
- if (SshConfigFileReader.parseBooleanValue(bannerOption)) {
- bannerOption = ServerAuthenticationManager.AUTO_WELCOME_BANNER_VALUE;
- }
- }
-
- Object banner;
- if (GenericUtils.isNotEmpty(bannerOption)) {
- if ("none".equals(bannerOption)) {
- return null;
- }
-
- if (ServerAuthenticationManager.AUTO_WELCOME_BANNER_VALUE.equalsIgnoreCase(bannerOption)) {
- banner = bannerOption;
- } else {
- banner = Paths.get(bannerOption);
- }
- } else {
- banner = "Welcome to SSHD\n";
- }
+ public static ForwardingFilter setupServerForwarding(SshServer server, Map<String, ?> options) {
+ ForwardingFilter forwardFilter = SshServerConfigFileReader.resolveServerForwarding(options);
+ server.setForwardingFilter(forwardFilter);
+ return forwardFilter;
+ }
+ public static Object setupServerBanner(ServerFactoryManager server, Map<String, ?> options) {
+ Object banner = SshServerConfigFileReader.resolveBanner(options);
PropertyResolverUtils.updateProperty(server, ServerAuthenticationManager.WELCOME_BANNER, banner);
return banner;
}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/aa551bc0/sshd-core/src/main/java/org/apache/sshd/server/channel/ChannelSession.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/channel/ChannelSession.java b/sshd-core/src/main/java/org/apache/sshd/server/channel/ChannelSession.java
index 053d2bc..44a5087 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/channel/ChannelSession.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/channel/ChannelSession.java
@@ -71,7 +71,8 @@ import org.apache.sshd.server.ServerFactoryManager;
import org.apache.sshd.server.SessionAware;
import org.apache.sshd.server.Signal;
import org.apache.sshd.server.StandardEnvironment;
-import org.apache.sshd.server.forward.ForwardingFilter;
+import org.apache.sshd.server.forward.AgentForwardingFilter;
+import org.apache.sshd.server.forward.X11ForwardingFilter;
import org.apache.sshd.server.session.ServerSession;
import org.apache.sshd.server.x11.X11ForwardSupport;
@@ -700,7 +701,7 @@ public class ChannelSession extends AbstractServerChannel {
ServerSession session = getServerSession();
PropertyResolverUtils.updateProperty(session, FactoryManager.AGENT_FORWARDING_TYPE, requestType);
FactoryManager manager = Objects.requireNonNull(session.getFactoryManager(), "No session factory manager");
- ForwardingFilter filter = manager.getTcpipForwardingFilter();
+ AgentForwardingFilter filter = manager.getAgentForwardingFilter();
SshAgentFactory factory = manager.getAgentFactory();
try {
if ((factory == null) || (filter == null) || (!filter.canForwardAgent(session, requestType))) {
@@ -739,7 +740,7 @@ public class ChannelSession extends AbstractServerChannel {
int screenId = buffer.getInt();
FactoryManager manager = Objects.requireNonNull(session.getFactoryManager(), "No factory manager");
- ForwardingFilter filter = manager.getTcpipForwardingFilter();
+ X11ForwardingFilter filter = manager.getX11ForwardingFilter();
try {
if ((filter == null) || (!filter.canForwardX11(session, requestType))) {
if (log.isDebugEnabled()) {
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/aa551bc0/sshd-core/src/main/java/org/apache/sshd/server/config/AllowTcpForwardingValue.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/config/AllowTcpForwardingValue.java b/sshd-core/src/main/java/org/apache/sshd/server/config/AllowTcpForwardingValue.java
new file mode 100644
index 0000000..ed6d7f8
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/server/config/AllowTcpForwardingValue.java
@@ -0,0 +1,106 @@
+/*
+ * 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.server.config;
+
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.Set;
+
+import org.apache.sshd.common.session.Session;
+import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.common.util.net.SshdSocketAddress;
+import org.apache.sshd.server.forward.TcpForwardingFilter;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ * @see <A HREF="http://www.freebsd.org/cgi/man.cgi?query=sshd_config&sektion=5">sshd_config(5) section</A>
+ */
+public enum AllowTcpForwardingValue implements TcpForwardingFilter {
+ ALL {
+ @Override
+ public boolean canListen(SshdSocketAddress address, Session session) {
+ return true;
+ }
+
+ @Override
+ public boolean canConnect(Type type, SshdSocketAddress address, Session session) {
+ return true;
+ }
+ },
+ NONE {
+ @Override
+ public boolean canListen(SshdSocketAddress address, Session session) {
+ return false;
+ }
+
+ @Override
+ public boolean canConnect(Type type, SshdSocketAddress address, Session session) {
+ return false;
+ }
+ },
+ LOCAL {
+ @Override
+ public boolean canListen(SshdSocketAddress address, Session session) {
+ return true;
+ }
+
+ @Override
+ public boolean canConnect(Type type, SshdSocketAddress address, Session session) {
+ return false;
+ }
+ },
+ REMOTE {
+ @Override
+ public boolean canListen(SshdSocketAddress address, Session session) {
+ return false;
+ }
+
+ @Override
+ public boolean canConnect(Type type, SshdSocketAddress address, Session session) {
+ return true;
+ }
+ };
+
+ public static final Set<AllowTcpForwardingValue> VALUES =
+ Collections.unmodifiableSet(EnumSet.allOf(AllowTcpForwardingValue.class));
+
+ // NOTE: it also interprets "yes" as "all" and "no" as "none"
+ public static AllowTcpForwardingValue fromString(String s) {
+ if (GenericUtils.isEmpty(s)) {
+ return null;
+ }
+
+ if ("yes".equalsIgnoreCase(s)) {
+ return ALL;
+ }
+
+ if ("no".equalsIgnoreCase(s)) {
+ return NONE;
+ }
+
+ for (AllowTcpForwardingValue v : VALUES) {
+ if (s.equalsIgnoreCase(v.name())) {
+ return v;
+ }
+ }
+
+ return null;
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/aa551bc0/sshd-core/src/main/java/org/apache/sshd/server/config/SshServerConfigFileReader.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/config/SshServerConfigFileReader.java b/sshd-core/src/main/java/org/apache/sshd/server/config/SshServerConfigFileReader.java
new file mode 100644
index 0000000..c5acd09
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/server/config/SshServerConfigFileReader.java
@@ -0,0 +1,111 @@
+/*
+ * 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.server.config;
+
+import java.nio.file.Paths;
+import java.util.Map;
+
+import org.apache.sshd.common.PropertyResolverUtils;
+import org.apache.sshd.common.config.SshConfigFileReader;
+import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.common.util.ValidateUtils;
+import org.apache.sshd.server.ServerAuthenticationManager;
+import org.apache.sshd.server.forward.AcceptAllForwardingFilter;
+import org.apache.sshd.server.forward.AgentForwardingFilter;
+import org.apache.sshd.server.forward.ForwardingFilter;
+import org.apache.sshd.server.forward.TcpForwardingFilter;
+import org.apache.sshd.server.forward.X11ForwardingFilter;
+
+/**
+ * Reads and interprets some useful configurations from an OpenSSH
+ * configuration file.
+ *
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ * @see <a href="http://www.freebsd.org/cgi/man.cgi?query=sshd_config&sektion=5">sshd_config(5)</a>
+ */
+public final class SshServerConfigFileReader {
+ // Some well known configuration properties names and values
+ public static final String ALLOW_TCP_FORWARDING_CONFIG_PROP = "AllowTcpForwarding";
+ public static final String DEFAULT_TCP_FORWARDING = "yes";
+
+ public static final String ALLOW_AGENT_FORWARDING_CONFIG_PROP = "AllowAgentForwarding";
+ public static final String DEFAULT_AGENT_FORWARDING = "yes";
+
+ public static final String ALLOW_X11_FORWARDING_CONFIG_PROP = "X11Forwarding";
+ public static final String DEFAULT_X11_FORWARDING = "no";
+
+ public static final String BANNER_CONFIG_PROP = "Banner";
+
+ public static final String VISUAL_HOST_KEY = "VisualHostKey";
+ public static final String DEFAULT_VISUAL_HOST_KEY = "no";
+
+ private SshServerConfigFileReader() {
+ throw new UnsupportedOperationException("No instance allowed");
+ }
+
+ public static ForwardingFilter resolveServerForwarding(Map<String, ?> options) {
+ if (GenericUtils.isEmpty(options)) {
+ return AcceptAllForwardingFilter.INSTANCE;
+ }
+
+ AgentForwardingFilter agentFilter = resolveAgentForwardingFilter(options);
+ TcpForwardingFilter tcpFilter = resolveTcpForwardingFilter(options);
+ X11ForwardingFilter x11Filter = resolveX11ForwardingFilter(options);
+ return ForwardingFilter.asForwardingFilter(agentFilter, x11Filter, tcpFilter);
+ }
+
+ public static AgentForwardingFilter resolveAgentForwardingFilter(Map<String, ?> options) {
+ String value = PropertyResolverUtils.getStringProperty(options, ALLOW_AGENT_FORWARDING_CONFIG_PROP, DEFAULT_AGENT_FORWARDING);
+ return AgentForwardingFilter.of(SshConfigFileReader.parseBooleanValue(value));
+ }
+
+ public static TcpForwardingFilter resolveTcpForwardingFilter(Map<String, ?> options) {
+ String value = PropertyResolverUtils.getStringProperty(options, ALLOW_TCP_FORWARDING_CONFIG_PROP, DEFAULT_TCP_FORWARDING);
+ TcpForwardingFilter filter = AllowTcpForwardingValue.fromString(value);
+ ValidateUtils.checkNotNull(filter, "Unknown %s value: %s", ALLOW_TCP_FORWARDING_CONFIG_PROP, value);
+ return filter;
+ }
+
+ public static X11ForwardingFilter resolveX11ForwardingFilter(Map<String, ?> options) {
+ String value = PropertyResolverUtils.getStringProperty(options, ALLOW_X11_FORWARDING_CONFIG_PROP, DEFAULT_X11_FORWARDING);
+ return X11ForwardingFilter.of(SshConfigFileReader.parseBooleanValue(value));
+ }
+
+ public static Object resolveBanner(Map<String, ?> options) {
+ String bannerOption = PropertyResolverUtils.getString(options, BANNER_CONFIG_PROP);
+ if (GenericUtils.isEmpty(bannerOption)) {
+ bannerOption = PropertyResolverUtils.getStringProperty(options, VISUAL_HOST_KEY, DEFAULT_VISUAL_HOST_KEY);
+ if (SshConfigFileReader.parseBooleanValue(bannerOption)) {
+ bannerOption = ServerAuthenticationManager.AUTO_WELCOME_BANNER_VALUE;
+ } else {
+ bannerOption = null;
+ }
+ }
+
+ if (GenericUtils.isEmpty(bannerOption)) {
+ return "Welcome to SSHD\n";
+ } else if ("none".equals(bannerOption)) {
+ return null;
+ } else if (ServerAuthenticationManager.AUTO_WELCOME_BANNER_VALUE.equalsIgnoreCase(bannerOption)) {
+ return bannerOption;
+ } else {
+ return Paths.get(bannerOption);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/aa551bc0/sshd-core/src/main/java/org/apache/sshd/server/forward/AgentForwardingFilter.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/forward/AgentForwardingFilter.java b/sshd-core/src/main/java/org/apache/sshd/server/forward/AgentForwardingFilter.java
new file mode 100644
index 0000000..97aaf12
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/server/forward/AgentForwardingFilter.java
@@ -0,0 +1,51 @@
+/*
+ * 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.server.forward;
+
+import org.apache.sshd.common.session.Session;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+@FunctionalInterface
+public interface AgentForwardingFilter {
+ // According to https://www.freebsd.org/cgi/man.cgi?query=sshd_config&sektion=5
+ AgentForwardingFilter DEFAULT = (session, requestType) -> true;
+
+ /**
+ * <p>
+ * Determine if the session may arrange for agent forwarding.
+ * </p>
+ *
+ * <p>
+ * This server process will open a new listen socket locally and export
+ * the address in the {@link org.apache.sshd.agent.SshAgent#SSH_AUTHSOCKET_ENV_NAME} environment
+ * variable.
+ * </p>
+ *
+ * @param session The {@link Session} requesting permission to forward the agent.
+ * @param requestType The request type string that triggered this call
+ * @return true if the agent forwarding is permitted, false if denied.
+ */
+ boolean canForwardAgent(Session session, String requestType);
+
+ static AgentForwardingFilter of(boolean enabled) {
+ return (session, requestType) -> enabled;
+ }
+}