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 2019/09/23 04:51:20 UTC
[mina-sshd] branch master updated: [SSHD-942] Added
ChannelIdTrackingUnknownChannelReferenceHandler
This is an automated email from the ASF dual-hosted git repository.
lgoldstein pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mina-sshd.git
The following commit(s) were added to refs/heads/master by this push:
new 11b33de [SSHD-942] Added ChannelIdTrackingUnknownChannelReferenceHandler
11b33de is described below
commit 11b33dee37b5b9c71a40a8a98a42007e3687131e
Author: Lyor Goldstein <lg...@apache.org>
AuthorDate: Mon Sep 23 07:44:28 2019 +0300
[SSHD-942] Added ChannelIdTrackingUnknownChannelReferenceHandler
---
CHANGES.md | 4 ++
docs/event-listeners.md | 4 ++
...elIdTrackingUnknownChannelReferenceHandler.java | 83 ++++++++++++++++++++++
.../DefaultUnknownChannelReferenceHandler.java | 16 +++--
4 files changed, 101 insertions(+), 6 deletions(-)
diff --git a/CHANGES.md b/CHANGES.md
index 7f77a16..1de1064 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -36,6 +36,10 @@ the standard does not specifically specify the behavior regarding symbolic links
* `SessionListener` supports `sessionPeerIdentificationReceived` that is invoked once successful
peer version data is received.
+* `ChannelIdTrackingUnknownChannelReferenceHandler` extends the functionality of the `DefaultUnknownChannelReferenceHandler`
+by tracking the initialized channels identifiers and being lenient only if command is received for a channel that was
+initialized in the past.
+
## Behavioral changes and enhancements
* [SSHD-926](https://issues.apache.org/jira/browse/SSHD-930) - Add support for OpenSSH 'lsetstat@openssh.com' SFTP protocol extension.
diff --git a/docs/event-listeners.md b/docs/event-listeners.md
index 476ec13..49a4a83 100644
--- a/docs/event-listeners.md
+++ b/docs/event-listeners.md
@@ -80,6 +80,10 @@ and logs them at DEBUG level. For a select few types of messages the code genera
peer session - see `DefaultUnknownChannelReferenceHandler` implementation. The user may register handlers at any level - client/server, session
and/or connection service - the one registered "closest" to connection service will be used.
+An **experimental** `ChannelIdTrackingUnknownChannelReferenceHandler` is available in _sshd-contrib_ package that applies the "leniency" of
+the `DefaultUnknownChannelReferenceHandler` only if the unknown channel is one that has been assigned in the past - otherwise it throws an
+exception. In order to use it, the handler instance needs to be registered as **both** an `UnknownChannelReferenceHandler` and a `ChannelListener`.
+
### `KexExtensionHandler`
Provides hooks for implementing [KEX extension negotiation](https://tools.ietf.org/html/rfc8308).
diff --git a/sshd-contrib/src/main/java/org/apache/sshd/common/session/helpers/ChannelIdTrackingUnknownChannelReferenceHandler.java b/sshd-contrib/src/main/java/org/apache/sshd/common/session/helpers/ChannelIdTrackingUnknownChannelReferenceHandler.java
new file mode 100644
index 0000000..bb6498b
--- /dev/null
+++ b/sshd-contrib/src/main/java/org/apache/sshd/common/session/helpers/ChannelIdTrackingUnknownChannelReferenceHandler.java
@@ -0,0 +1,83 @@
+/*
+ * 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.session.helpers;
+
+import java.io.IOException;
+
+import org.apache.sshd.common.AttributeRepository.AttributeKey;
+import org.apache.sshd.common.SshConstants;
+import org.apache.sshd.common.channel.Channel;
+import org.apache.sshd.common.channel.ChannelListener;
+import org.apache.sshd.common.channel.exception.SshChannelNotFoundException;
+import org.apache.sshd.common.session.ConnectionService;
+import org.apache.sshd.common.session.Session;
+import org.apache.sshd.common.util.buffer.Buffer;
+
+/**
+ * Makes sure that the referenced "unknown" channel identifier
+ * is one that was assigned in the past. <B>Note:</B> it relies on the
+ * fact that the default {@code ConnectionService} implementation assigns
+ * channels identifiers in ascending order.
+ *
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class ChannelIdTrackingUnknownChannelReferenceHandler
+ extends DefaultUnknownChannelReferenceHandler
+ implements ChannelListener {
+ public static final AttributeKey<Integer> LAST_CHANNEL_ID_KEY = new AttributeKey<>();
+
+ public static final ChannelIdTrackingUnknownChannelReferenceHandler TRACKER =
+ new ChannelIdTrackingUnknownChannelReferenceHandler();
+
+ public ChannelIdTrackingUnknownChannelReferenceHandler() {
+ super();
+ }
+
+ @Override
+ public void channelInitialized(Channel channel) {
+ int channelId = channel.getId();
+ Session session = channel.getSession();
+ Integer lastTracked = session.setAttribute(LAST_CHANNEL_ID_KEY, channelId);
+ if (log.isDebugEnabled()) {
+ log.debug("channelInitialized({}) updated last tracked channel ID {} => {}",
+ channel, lastTracked, channelId);
+ }
+ }
+
+ @Override
+ public Channel handleUnknownChannelCommand(
+ ConnectionService service, byte cmd, int channelId, Buffer buffer)
+ throws IOException {
+ Session session = service.getSession();
+ Integer lastTracked = session.getAttribute(LAST_CHANNEL_ID_KEY);
+ if ((lastTracked != null) && (channelId <= lastTracked.intValue())) {
+ // Use TRACE level in order to avoid messages flooding
+ if (log.isTraceEnabled()) {
+ log.trace("handleUnknownChannelCommand({}) apply default handling for {} on channel={} (lastTracked={})",
+ session, SshConstants.getCommandMessageName(cmd), channelId, lastTracked);
+ }
+ return super.handleUnknownChannelCommand(service, cmd, channelId, buffer);
+ }
+
+ throw new SshChannelNotFoundException(channelId,
+ "Received " + SshConstants.getCommandMessageName(cmd) + " on unassigned channel " + channelId
+ + " (last assigned=" + lastTracked + ")");
+ }
+}
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/session/helpers/DefaultUnknownChannelReferenceHandler.java b/sshd-core/src/main/java/org/apache/sshd/common/session/helpers/DefaultUnknownChannelReferenceHandler.java
index 76ebec2..8438ca7 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/session/helpers/DefaultUnknownChannelReferenceHandler.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/session/helpers/DefaultUnknownChannelReferenceHandler.java
@@ -55,13 +55,13 @@ public class DefaultUnknownChannelReferenceHandler
@Override
public Channel handleUnknownChannelCommand(
ConnectionService service, byte cmd, int channelId, Buffer buffer)
- throws IOException {
+ throws IOException {
Session session = service.getSession();
// Use DEBUG level to avoid log overflow due to invalid messages flood
boolean debugEnabled = log.isDebugEnabled();
if (debugEnabled) {
log.debug("handleUnknownChannelCommand({}) received {} command for unknown channel: {}",
- session, SshConstants.getCommandMessageName(cmd), channelId);
+ session, SshConstants.getCommandMessageName(cmd), channelId);
}
boolean wantReply = false;
@@ -85,10 +85,12 @@ public class DefaultUnknownChannelReferenceHandler
case SshConstants.SSH_MSG_CHANNEL_DATA:
case SshConstants.SSH_MSG_CHANNEL_EXTENDED_DATA:
- wantReply = PropertyResolverUtils.getBooleanProperty(session, SEND_REPLY_FOR_CHANNEL_DATA, DEFAULT_SEND_REPLY_FOR_CHANNEL_DATA);
+ wantReply = PropertyResolverUtils.getBooleanProperty(
+ session, SEND_REPLY_FOR_CHANNEL_DATA, DEFAULT_SEND_REPLY_FOR_CHANNEL_DATA);
// Use TRACE level to avoid log overflow due to invalid messages flood
if (log.isTraceEnabled()) {
- log.trace("handleUnknownChannelCommand({}) received msg channel data (opcode={}) reply={}", session, cmd, wantReply);
+ log.trace("handleUnknownChannelCommand({}) received msg channel data (opcode={}) reply={}",
+ session, cmd, wantReply);
}
break;
@@ -102,12 +104,14 @@ public class DefaultUnknownChannelReferenceHandler
return null;
}
- protected IoWriteFuture sendFailureResponse(ConnectionService service, byte cmd, int channelId) throws IOException {
+ protected IoWriteFuture sendFailureResponse(
+ ConnectionService service, byte cmd, int channelId)
+ throws IOException {
Session session = service.getSession();
// Use DEBUG level to avoid log overflow due to invalid messages flood
if (log.isDebugEnabled()) {
log.debug("sendFailureResponse({}) send SSH_MSG_CHANNEL_FAILURE for {} command on unknown channel: {}",
- session, SshConstants.getCommandMessageName(cmd), channelId);
+ session, SshConstants.getCommandMessageName(cmd), channelId);
}
Buffer rsp = session.createBuffer(SshConstants.SSH_MSG_CHANNEL_FAILURE, Integer.BYTES);