Skip to content

Commit beb09ac

Browse files
committed
Handle unknown channel messages correctly
See discussion #1218 . Some servers send custom channel messages like '[email protected]' as keep alive messages. This currently causes a NotSupportedException. According to the spec https://datatracker.ietf.org/doc/html/rfc4254#section-5.4 : "If the request is not recognized or is not supported for the channel, SSH_MSG_CHANNEL_FAILURE is returned." Send a failure message back instead of throwing an exception.
1 parent 3e6fc4f commit beb09ac

File tree

2 files changed

+72
-3
lines changed

2 files changed

+72
-3
lines changed

src/Renci.SshNet/Channels/Channel.cs

+2-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
using System;
2-
using System.Globalization;
32
using System.Net.Sockets;
43
using System.Threading;
54

@@ -715,8 +714,8 @@ private void OnChannelRequest(object sender, MessageEventArgs<ChannelRequestMess
715714
}
716715
else
717716
{
718-
// TODO: we should also send a SSH_MSG_CHANNEL_FAILURE message
719-
throw new NotSupportedException(string.Format(CultureInfo.CurrentCulture, "Request '{0}' is not supported.", e.Message.RequestName));
717+
var reply = new ChannelFailureMessage(LocalChannelNumber);
718+
SendMessage(reply);
720719
}
721720
}
722721
catch (Exception ex)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
using System;
2+
using System.Collections.Generic;
3+
4+
using Microsoft.VisualStudio.TestTools.UnitTesting;
5+
6+
using Renci.SshNet.Common;
7+
using Renci.SshNet.Messages.Connection;
8+
9+
namespace Renci.SshNet.Tests.Classes.Channels
10+
{
11+
[TestClass]
12+
public class ChannelTest_OnSessionChannelRequestReceived_HandleUnknownMessage : ChannelTestBase
13+
{
14+
private uint _localWindowSize;
15+
private uint _localPacketSize;
16+
private uint _localChannelNumber;
17+
private ChannelStub _channel;
18+
private IList<ExceptionEventArgs> _channelExceptionRegister;
19+
private UnknownRequestInfo _requestInfo;
20+
21+
protected override void SetupData()
22+
{
23+
var random = new Random();
24+
25+
_localWindowSize = (uint) random.Next(1000, int.MaxValue);
26+
_localPacketSize = _localWindowSize - 1;
27+
_localChannelNumber = (uint) random.Next(0, int.MaxValue);
28+
_channelExceptionRegister = new List<ExceptionEventArgs>();
29+
_requestInfo = new UnknownRequestInfo();
30+
}
31+
32+
protected override void SetupMocks()
33+
{
34+
_ = SessionMock.Setup(p => p.ConnectionInfo)
35+
.Returns(new ConnectionInfo("host", "user", new PasswordAuthenticationMethod("user", "password")));
36+
}
37+
38+
protected override void Arrange()
39+
{
40+
base.Arrange();
41+
42+
_channel = new ChannelStub(SessionMock.Object, _localChannelNumber, _localWindowSize, _localPacketSize);
43+
_channel.Exception += (sender, args) => _channelExceptionRegister.Add(args);
44+
}
45+
46+
protected override void Act()
47+
{
48+
SessionMock.Raise(s => s.ChannelRequestReceived += null,
49+
new MessageEventArgs<ChannelRequestMessage>(new ChannelRequestMessage(_localChannelNumber, _requestInfo)));
50+
}
51+
52+
[TestMethod]
53+
public void NoExceptionShouldHaveFired()
54+
{
55+
Assert.AreEqual(0, _channelExceptionRegister.Count);
56+
}
57+
}
58+
59+
internal class UnknownRequestInfo : RequestInfo
60+
{
61+
public override string RequestName
62+
{
63+
get
64+
{
65+
return nameof(UnknownRequestInfo);
66+
}
67+
}
68+
69+
}
70+
}

0 commit comments

Comments
 (0)