<PackageReference Include="SSH.NET" Version="2020.0.0" />

ProtocolVersionExchange

Handles the SSH protocol version exchange.
using Renci.SshNet.Abstractions; using Renci.SshNet.Common; using Renci.SshNet.Messages.Transport; using System; using System.Collections.Generic; using System.Globalization; using System.Net.Sockets; using System.Text; using System.Text.RegularExpressions; namespace Renci.SshNet.Connection { internal class ProtocolVersionExchange : IProtocolVersionExchange { private const byte Null = 0; private static readonly Regex ServerVersionRe = new Regex("^SSH-(?<protoversion>[^-]+)-(?<softwareversion>.+?)([ ](?<comments>.+))?$"); public SshIdentification Start(string clientVersion, Socket socket, TimeSpan timeout) { SocketAbstraction.Send(socket, Encoding.UTF8.GetBytes(clientVersion + "\r\n")); List<byte> list = new List<byte>(); Match match; do { string text = SocketReadLine(socket, timeout, list); if (text == null) { if (list.Count == 0) throw new SshConnectionException(string.Format("The server response does not contain an SSH identification string.{0}The connection to the remote server was closed before any data was received.{0}{0}More information on the Protocol Version Exchange is available here:{0}https://tools.ietf.org/html/rfc4253#section-4.2", Environment.NewLine), DisconnectReason.ConnectionLost); throw new SshConnectionException(string.Format("The server response does not contain an SSH identification string:{0}{0}{1}{0}{0}More information on the Protocol Version Exchange is available here:{0}https://tools.ietf.org/html/rfc4253#section-4.2", Environment.NewLine, PacketDump.Create(list, 2)), DisconnectReason.ProtocolError); } match = ServerVersionRe.Match(text); } while (!match.Success); return new SshIdentification(GetGroupValue(match, "protoversion"), GetGroupValue(match, "softwareversion"), GetGroupValue(match, "comments")); } private static string GetGroupValue(Match match, string groupName) { Group group = match.Groups[groupName]; if (group.Success) return group.Value; return null; } private static string SocketReadLine(Socket socket, TimeSpan timeout, List<byte> buffer) { byte[] array = new byte[1]; int count = buffer.Count; while (SocketAbstraction.Read(socket, array, 0, array.Length, timeout) != 0) { byte b = array[0]; buffer.Add(b); switch (b) { case 0: throw new SshConnectionException(string.Format(CultureInfo.InvariantCulture, "The server response contains a null character at position 0x{0:X8}:{1}{1}{2}{1}{1}A server must not send a null character before the Protocol Version Exchange is complete.{1}{1}More information is available here:{1}https://tools.ietf.org/html/rfc4253#section-4.2", buffer.Count, Environment.NewLine, PacketDump.Create(buffer.ToArray(), 2))); case 10: if (buffer.Count > count + 1 && buffer[buffer.Count - 2] == 13) return Encoding.UTF8.GetString(buffer.ToArray(), count, buffer.Count - (count + 2)); break; } } return null; } } }