You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mina.apache.org by sp...@apache.org on 2009/11/17 04:26:30 UTC
svn commit: r881138 - in /mina/sshd/trunk/sshd-core/src:
main/java/org/apache/sshd/ main/java/org/apache/sshd/server/
main/java/org/apache/sshd/server/channel/
main/java/org/apache/sshd/server/session/ test/java/org/apache/sshd/
test/java/org/apache/ss...
Author: spearce
Date: Tue Nov 17 03:26:29 2009
New Revision: 881138
URL: http://svn.apache.org/viewvc?rev=881138&view=rev
Log:
SSHD-60: Filter TCP/IP port forwarding requests and fix stream close
Aside from filtering the port forwarding requests we also now notify
a client when the peer it has forwarded a port to has disconnected.
Added:
mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/server/TcpIpForwardFilter.java
mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/server/channel/OpenChannelException.java
mina/sshd/trunk/sshd-core/src/test/java/org/apache/sshd/util/BogusTcpIpForwardFilter.java
Modified:
mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/SshServer.java
mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/server/ServerFactoryManager.java
mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/server/channel/ChannelDirectTcpip.java
mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/server/session/ServerSession.java
mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/server/session/TcpipForwardSupport.java
mina/sshd/trunk/sshd-core/src/test/java/org/apache/sshd/PortForwardingTest.java
Modified: mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/SshServer.java
URL: http://svn.apache.org/viewvc/mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/SshServer.java?rev=881138&r1=881137&r2=881138&view=diff
==============================================================================
--- mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/SshServer.java (original)
+++ mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/SshServer.java Tue Nov 17 03:26:29 2009
@@ -103,6 +103,7 @@
protected List<NamedFactory<Command>> subsystemFactories;
protected PasswordAuthenticator passwordAuthenticator;
protected PublickeyAuthenticator publickeyAuthenticator;
+ protected TcpIpForwardFilter tcpIpForwardFilter;
public SshServer() {
}
@@ -200,6 +201,14 @@
this.publickeyAuthenticator = publickeyAuthenticator;
}
+ public TcpIpForwardFilter getTcpIpForwardFilter() {
+ return tcpIpForwardFilter;
+ }
+
+ public void setTcpIpForwardFilter(TcpIpForwardFilter tcpIpForwardFilter) {
+ this.tcpIpForwardFilter = tcpIpForwardFilter;
+ }
+
protected void checkConfig() {
if (getPort() < 0) {
throw new IllegalArgumentException("Bad port number: " + port);
@@ -401,6 +410,15 @@
return username != null && username.equals(password);
}
});
+ sshd.setTcpIpForwardFilter(new TcpIpForwardFilter() {
+ public boolean canListen(InetSocketAddress address, ServerSession session) {
+ return true;
+ }
+
+ public boolean canConnect(InetSocketAddress address, ServerSession session) {
+ return true;
+ }
+ });
sshd.start();
}
Modified: mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/server/ServerFactoryManager.java
URL: http://svn.apache.org/viewvc/mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/server/ServerFactoryManager.java?rev=881138&r1=881137&r2=881138&view=diff
==============================================================================
--- mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/server/ServerFactoryManager.java (original)
+++ mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/server/ServerFactoryManager.java Tue Nov 17 03:26:29 2009
@@ -60,6 +60,15 @@
PasswordAuthenticator getPasswordAuthenticator();
/**
+ * Retrieve the <code>TcpIpForwardFilter</code> to be used by the SSH server.
+ * If no filter has been configured (i.e. this method returns
+ * <code>null</code>), then all forwarding requests will be rejected.
+ *
+ * @return the <code>TcpIpForwardFilter</code> or <code>null</code>
+ */
+ TcpIpForwardFilter getTcpIpForwardFilter();
+
+ /**
* Retrieve the <code>ShellFactory</code> object to be used to create shells.
*
* @return a valid <code>ShellFactory</code> object or <code>null</code> if shells
Added: mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/server/TcpIpForwardFilter.java
URL: http://svn.apache.org/viewvc/mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/server/TcpIpForwardFilter.java?rev=881138&view=auto
==============================================================================
--- mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/server/TcpIpForwardFilter.java (added)
+++ mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/server/TcpIpForwardFilter.java Tue Nov 17 03:26:29 2009
@@ -0,0 +1,61 @@
+/*
+ * 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;
+
+import org.apache.sshd.server.session.ServerSession;
+
+import java.net.InetSocketAddress;
+
+/**
+ * Determines if a TCP/IP forwarding will be permitted.
+ *
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public interface TcpIpForwardFilter {
+ /**
+ * Determine if the session may listen for inbound connections.
+ * <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.
+ *
+ * @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 canListen(InetSocketAddress address, ServerSession session);
+
+ /**
+ * Determine if the session may create an outbound connection.
+ * <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.
+ *
+ * @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(InetSocketAddress address, ServerSession session);
+}
Modified: mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/server/channel/ChannelDirectTcpip.java
URL: http://svn.apache.org/viewvc/mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/server/channel/ChannelDirectTcpip.java?rev=881138&r1=881137&r2=881138&view=diff
==============================================================================
--- mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/server/channel/ChannelDirectTcpip.java (original)
+++ mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/server/channel/ChannelDirectTcpip.java Tue Nov 17 03:26:29 2009
@@ -21,6 +21,7 @@
import java.io.IOException;
import java.io.InterruptedIOException;
import java.io.OutputStream;
+import java.net.ConnectException;
import java.net.InetSocketAddress;
import org.apache.mina.core.buffer.IoBuffer;
@@ -41,6 +42,8 @@
import org.apache.sshd.common.future.SshFuture;
import org.apache.sshd.common.future.SshFutureListener;
import org.apache.sshd.common.util.Buffer;
+import org.apache.sshd.server.TcpIpForwardFilter;
+import org.apache.sshd.server.session.ServerSession;
/**
* TODO Add javadoc
@@ -71,6 +74,16 @@
final OpenFuture f = new DefaultOpenFuture(this);
String hostToConnect = buffer.getString();
int portToConnect = buffer.getInt();
+ InetSocketAddress address = new InetSocketAddress(hostToConnect, portToConnect);
+
+ final ServerSession serverSession = (ServerSession)getSession();
+ final TcpIpForwardFilter filter = serverSession.getServerFactoryManager().getTcpIpForwardFilter();
+ if (filter == null || !filter.canConnect(address, serverSession)) {
+ super.close(true);
+ f.setException(new OpenChannelException(SshConstants.SSH_OPEN_ADMINISTRATIVELY_PROHIBITED, "connect denied"));
+ return f;
+ }
+
String originatorIpAddress = buffer.getString();
int originatorPort = buffer.getInt();
log.info("Receiving request for direct tcpip: hostToConnect={}, portToConnect={}, originatorIpAddress={}, originatorPort={}",
@@ -87,27 +100,61 @@
out.write(b, 0, r);
out.flush();
}
+
+ @Override
+ public void sessionClosed(IoSession session) throws Exception {
+ sendEof();
+ }
};
connector.setHandler(handler);
- ConnectFuture future = connector.connect(new InetSocketAddress(hostToConnect, portToConnect));
+ ConnectFuture future = connector.connect(address);
future.addListener(new IoFutureListener<ConnectFuture>() {
public void operationComplete(ConnectFuture future) {
if (future.isConnected()) {
ioSession = future.getSession();
f.setOpened();
} else if (future.getException() != null) {
- close(false);
- f.setException(future.getException());
+ closeImmediately0();
+ if (future.getException() instanceof ConnectException) {
+ f.setException(new OpenChannelException(
+ SshConstants.SSH_OPEN_CONNECT_FAILED,
+ future.getException().getMessage(),
+ future.getException()));
+ } else {
+ f.setException(future.getException());
+ }
}
}
});
return f;
}
+ private void closeImmediately0() {
+ // We need to close the channel immediately to remove it from the
+ // server session's channel table and *not* send a packet to the
+ // client. A notification was already sent by our caller, or will
+ // be sent after we return.
+ //
+ super.close(true);
+
+ // We also need to dispose of the connector, but unfortunately we
+ // are being invoked by the connector thread or the connector's
+ // own processor thread. Disposing of the connector within either
+ // causes deadlock. Instead create a new thread to dispose of the
+ // connector in the background.
+ //
+ new Thread("ChannelDirectTcpip-ConnectorCleanup") {
+ @Override
+ public void run() {
+ connector.dispose();
+ }
+ }.start();
+ }
+
public CloseFuture close(boolean immediately) {
return super.close(immediately).addListener(new SshFutureListener() {
public void operationComplete(SshFuture sshFuture) {
- connector.dispose();
+ closeImmediately0();
}
});
}
Added: mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/server/channel/OpenChannelException.java
URL: http://svn.apache.org/viewvc/mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/server/channel/OpenChannelException.java?rev=881138&view=auto
==============================================================================
--- mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/server/channel/OpenChannelException.java (added)
+++ mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/server/channel/OpenChannelException.java Tue Nov 17 03:26:29 2009
@@ -0,0 +1,54 @@
+/*
+ * 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.channel;
+
+import org.apache.sshd.common.SshConstants;
+
+/**
+ * Documents failure of a channel to open as expected.
+ *
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class OpenChannelException extends Exception {
+ private final int code;
+
+ public OpenChannelException(int code, String message) {
+ this(code, message, null);
+ }
+
+ public OpenChannelException(int code, String message, Throwable cause) {
+ super(message, cause);
+ this.code = code;
+ }
+
+ /**
+ * The reason code as specified by RFC 4254.
+ * <ul>
+ * <li>{@link SshConstants#SSH_OPEN_ADMINISTRATIVELY_PROHIBITED}
+ * <li>{@link SshConstants#SSH_OPEN_CONNECT_FAILED}
+ * <li>{@link SshConstants#SSH_OPEN_UNKNOWN_CHANNEL_TYPE}
+ * <li>{@link SshConstants#SSH_OPEN_RESOURCE_SHORTAGE}
+ * </ul>
+ *
+ * @return reason code; 0 if no standardized reason code is given.
+ */
+ public int getReasonCode() {
+ return code;
+ }
+}
Modified: mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/server/session/ServerSession.java
URL: http://svn.apache.org/viewvc/mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/server/session/ServerSession.java?rev=881138&r1=881137&r2=881138&view=diff
==============================================================================
--- mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/server/session/ServerSession.java (original)
+++ mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/server/session/ServerSession.java Tue Nov 17 03:26:29 2009
@@ -39,6 +39,7 @@
import org.apache.sshd.common.util.Buffer;
import org.apache.sshd.server.ServerFactoryManager;
import org.apache.sshd.server.UserAuth;
+import org.apache.sshd.server.channel.OpenChannelException;;
/**
*
@@ -411,8 +412,13 @@
} else if (future.getException() != null) {
Buffer buf = createBuffer(SshConstants.Message.SSH_MSG_CHANNEL_OPEN_FAILURE);
buf.putInt(id);
- buf.putInt(0);
- buf.putString("Error opening channel: " + future.getException().getMessage());
+ if (future.getException() instanceof OpenChannelException) {
+ buf.putInt(((OpenChannelException)future.getException()).getReasonCode());
+ buf.putString(future.getException().getMessage());
+ } else {
+ buf.putInt(0);
+ buf.putString("Error opening channel: " + future.getException().getMessage());
+ }
buf.putString("");
writePacket(buf);
}
Modified: mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/server/session/TcpipForwardSupport.java
URL: http://svn.apache.org/viewvc/mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/server/session/TcpipForwardSupport.java?rev=881138&r1=881137&r2=881138&view=diff
==============================================================================
--- mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/server/session/TcpipForwardSupport.java (original)
+++ mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/server/session/TcpipForwardSupport.java Tue Nov 17 03:26:29 2009
@@ -34,21 +34,21 @@
import org.apache.sshd.client.channel.AbstractClientChannel;
import org.apache.sshd.client.future.DefaultOpenFuture;
import org.apache.sshd.client.future.OpenFuture;
-import org.apache.sshd.common.Session;
import org.apache.sshd.common.SshConstants;
import org.apache.sshd.common.SshException;
import org.apache.sshd.common.channel.ChannelOutputStream;
import org.apache.sshd.common.util.Buffer;
+import org.apache.sshd.server.TcpIpForwardFilter;
/**
* @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
*/
public class TcpipForwardSupport extends IoHandlerAdapter {
- private final Session session;
+ private final ServerSession session;
private IoAcceptor acceptor;
- public TcpipForwardSupport(Session session) {
+ public TcpipForwardSupport(ServerSession session) {
this.session = session;
}
@@ -65,15 +65,38 @@
public synchronized void close() {
if (acceptor != null) {
acceptor.dispose();
+ acceptor = null;
}
}
synchronized void request(Buffer buffer, boolean wantReply) throws IOException {
- initialize();
String address = buffer.getString();
int port = buffer.getInt();
+ InetSocketAddress addr = new InetSocketAddress(address, port);
+
+ final TcpIpForwardFilter filter = session.getServerFactoryManager().getTcpIpForwardFilter();
+ if (filter == null || !filter.canListen(addr, session)) {
+ if (wantReply) {
+ buffer = session.createBuffer(SshConstants.Message.SSH_MSG_REQUEST_FAILURE);
+ session.writePacket(buffer);
+ }
+ return;
+ }
+
+ initialize();
Set<SocketAddress> a1 = acceptor.getLocalAddresses();
- acceptor.bind(new InetSocketAddress(address, port));
+ try {
+ acceptor.bind(addr);
+ } catch (IOException bindErr) {
+ if (acceptor.getLocalAddresses().isEmpty()) {
+ close();
+ }
+ if (wantReply) {
+ buffer = session.createBuffer(SshConstants.Message.SSH_MSG_REQUEST_FAILURE);
+ session.writePacket(buffer);
+ }
+ return;
+ }
Set<SocketAddress> a2 = acceptor.getLocalAddresses();
a2.removeAll(a1);
if (a2.size() == 1) {
@@ -92,7 +115,9 @@
synchronized void cancel(Buffer buffer, boolean wantReply) throws IOException {
String address = buffer.getString();
int port = buffer.getInt();
- acceptor.unbind(new InetSocketAddress(address, port));
+ if (acceptor != null) {
+ acceptor.unbind(new InetSocketAddress(address, port));
+ }
if (wantReply) {
buffer = session.createBuffer(SshConstants.Message.SSH_MSG_REQUEST_SUCCESS);
session.writePacket(buffer);
@@ -185,6 +210,11 @@
serverSession.write(buf);
}
+ @Override
+ public void handleEof() throws IOException {
+ super.handleEof();
+ serverSession.close(false);
+ }
}
Modified: mina/sshd/trunk/sshd-core/src/test/java/org/apache/sshd/PortForwardingTest.java
URL: http://svn.apache.org/viewvc/mina/sshd/trunk/sshd-core/src/test/java/org/apache/sshd/PortForwardingTest.java?rev=881138&r1=881137&r2=881138&view=diff
==============================================================================
--- mina/sshd/trunk/sshd-core/src/test/java/org/apache/sshd/PortForwardingTest.java (original)
+++ mina/sshd/trunk/sshd-core/src/test/java/org/apache/sshd/PortForwardingTest.java Tue Nov 17 03:26:29 2009
@@ -37,6 +37,7 @@
import org.apache.mina.transport.socket.nio.NioSocketAcceptor;
import org.apache.sshd.common.keyprovider.FileKeyPairProvider;
import org.apache.sshd.util.BogusPasswordAuthenticator;
+import org.apache.sshd.util.BogusTcpIpForwardFilter;
import org.apache.sshd.util.EchoShellFactory;
import org.junit.After;
import org.junit.Before;
@@ -75,6 +76,7 @@
sshd.setKeyPairProvider(new FileKeyPairProvider(new String[] { "src/test/resources/hostkey.pem" }));
sshd.setShellFactory(new EchoShellFactory());
sshd.setPasswordAuthenticator(new BogusPasswordAuthenticator());
+ sshd.setTcpIpForwardFilter(new BogusTcpIpForwardFilter());
sshd.start();
NioSocketAcceptor acceptor = new NioSocketAcceptor();
Added: mina/sshd/trunk/sshd-core/src/test/java/org/apache/sshd/util/BogusTcpIpForwardFilter.java
URL: http://svn.apache.org/viewvc/mina/sshd/trunk/sshd-core/src/test/java/org/apache/sshd/util/BogusTcpIpForwardFilter.java?rev=881138&view=auto
==============================================================================
--- mina/sshd/trunk/sshd-core/src/test/java/org/apache/sshd/util/BogusTcpIpForwardFilter.java (added)
+++ mina/sshd/trunk/sshd-core/src/test/java/org/apache/sshd/util/BogusTcpIpForwardFilter.java Tue Nov 17 03:26:29 2009
@@ -0,0 +1,39 @@
+/*
+ * 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.util;
+
+import org.apache.sshd.server.TcpIpForwardFilter;
+import org.apache.sshd.server.session.ServerSession;
+
+import java.net.InetSocketAddress;
+
+/**
+ * TODO Add javadoc
+ *
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class BogusTcpIpForwardFilter implements TcpIpForwardFilter {
+ public boolean canConnect(InetSocketAddress address, ServerSession session) {
+ return true;
+ }
+
+ public boolean canListen(InetSocketAddress address, ServerSession session) {
+ return true;
+ }
+}