Skip to content

Cisco connection issue fix #841

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 9 commits into from
14 changes: 14 additions & 0 deletions src/Renci.SshNet/Connection/IProtocolVersionExchange.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,22 @@ internal interface IProtocolVersionExchange
/// </returns>
SshIdentification Start(string clientVersion, Socket socket, TimeSpan timeout);


/// <summary>
/// Performs the SSH protocol version exchange.
/// </summary>
/// <param name="clientVersion">The identification string of the SSH client.</param>
/// <param name="socket">A <see cref="Socket"/> connected to the server.</param>
/// <param name="timeout">The maximum time to wait for the server to respond.</param>
/// <param name="lazyIdentification">Allow server to identify itself first.</param>
/// <returns>
/// The SSH identification of the server.
/// </returns>
SshIdentification Start(string clientVersion, Socket socket, TimeSpan timeout, bool lazyIdentification);

#if FEATURE_TAP
System.Threading.Tasks.Task<SshIdentification> StartAsync(string clientVersion, Socket socket, System.Threading.CancellationToken cancellationToken);
#endif

}
}
30 changes: 27 additions & 3 deletions src/Renci.SshNet/Connection/ProtocolVersionExchange.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,27 @@ internal class ProtocolVersionExchange : IProtocolVersionExchange
/// </returns>
public SshIdentification Start(string clientVersion, Socket socket, TimeSpan timeout)
{
// Immediately send the identification string since the spec states both sides MUST send an identification string
// when the connection has been established
SocketAbstraction.Send(socket, Encoding.UTF8.GetBytes(clientVersion + "\x0D\x0A"));
return Start(clientVersion, socket, timeout, false);
}

/// <summary>
/// Performs the SSH protocol version exchange.
/// </summary>
/// <param name="clientVersion">The identification string of the SSH client.</param>
/// <param name="socket">A <see cref="Socket"/> connected to the server.</param>
/// <param name="timeout">The maximum time to wait for the server to respond.</param>
/// <param name="lazyIdentification">Allow server to identify itself first.</param>
/// <returns>
/// The SSH identification of the server.
/// </returns>
public SshIdentification Start(string clientVersion, Socket socket, TimeSpan timeout, bool lazyIdentification = false)
{
if (!lazyIdentification)
{
// Immediately send the identification string since the spec states both sides MUST send an identification string
// when the connection has been established
SocketAbstraction.Send(socket, Encoding.UTF8.GetBytes(clientVersion + "\x0D\x0A"));
}

var bytesReceived = new List<byte>();

Expand Down Expand Up @@ -75,6 +93,12 @@ public SshIdentification Start(string clientVersion, Socket socket, TimeSpan tim
var identificationMatch = ServerVersionRe.Match(line);
if (identificationMatch.Success)
{
if (lazyIdentification)
{
// Send identification only after server identification has been validated.
SocketAbstraction.Send(socket, Encoding.UTF8.GetBytes(clientVersion + "\x0D\x0A"));
}

return new SshIdentification(GetGroupValue(identificationMatch, "protoversion"),
GetGroupValue(identificationMatch, "softwareversion"),
GetGroupValue(identificationMatch, "comments"));
Expand Down
10 changes: 10 additions & 0 deletions src/Renci.SshNet/ConnectionInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,14 @@ public class ConnectionInfo : IConnectionInfoInternal
/// </value>
public int MaxSessions { get; set; }

/// <summary>
/// Gets or sets if the client should identify itself later.
/// </summary>
/// <value>
/// <c>false</c>, the default for strict RFC4253 compliance where both sides identify at the same time. <c>true</c> if the client should wait for the server identification.
/// </value>
public bool LazyIdentification { get; set; }

/// <summary>
/// Occurs when authentication banner is sent by the server.
/// </summary>
Expand Down Expand Up @@ -432,6 +440,8 @@ public ConnectionInfo(string host, int port, string username, ProxyTypes proxyTy
ProxyPassword = proxyPassword;

AuthenticationMethods = authenticationMethods;

LazyIdentification = false;
}

/// <summary>
Expand Down
2 changes: 1 addition & 1 deletion src/Renci.SshNet/Session.cs
Original file line number Diff line number Diff line change
Expand Up @@ -591,7 +591,7 @@ public void Connect()
.Connect(ConnectionInfo);

var serverIdentification = _serviceFactory.CreateProtocolVersionExchange()
.Start(ClientVersion, _socket, ConnectionInfo.Timeout);
.Start(ClientVersion, _socket, ConnectionInfo.Timeout, ConnectionInfo.LazyIdentification);

// Set connection versions
ServerVersion = ConnectionInfo.ServerVersion = serverIdentification.ToString();
Expand Down