|
|
@@ -300,20 +300,20 @@ namespace Renci.SshNet
|
|
|
if (_clientInitMessage == null)
|
|
|
{
|
|
|
_clientInitMessage = new KeyExchangeInitMessage
|
|
|
- {
|
|
|
- KeyExchangeAlgorithms = ConnectionInfo.KeyExchangeAlgorithms.Keys.ToArray(),
|
|
|
- ServerHostKeyAlgorithms = ConnectionInfo.HostKeyAlgorithms.Keys.ToArray(),
|
|
|
- EncryptionAlgorithmsClientToServer = ConnectionInfo.Encryptions.Keys.ToArray(),
|
|
|
- EncryptionAlgorithmsServerToClient = ConnectionInfo.Encryptions.Keys.ToArray(),
|
|
|
- MacAlgorithmsClientToServer = ConnectionInfo.HmacAlgorithms.Keys.ToArray(),
|
|
|
- MacAlgorithmsServerToClient = ConnectionInfo.HmacAlgorithms.Keys.ToArray(),
|
|
|
- CompressionAlgorithmsClientToServer = ConnectionInfo.CompressionAlgorithms.Keys.ToArray(),
|
|
|
- CompressionAlgorithmsServerToClient = ConnectionInfo.CompressionAlgorithms.Keys.ToArray(),
|
|
|
- LanguagesClientToServer = new[] {string.Empty},
|
|
|
- LanguagesServerToClient = new[] {string.Empty},
|
|
|
- FirstKexPacketFollows = false,
|
|
|
- Reserved = 0
|
|
|
- };
|
|
|
+ {
|
|
|
+ KeyExchangeAlgorithms = ConnectionInfo.KeyExchangeAlgorithms.Keys.ToArray(),
|
|
|
+ ServerHostKeyAlgorithms = ConnectionInfo.HostKeyAlgorithms.Keys.ToArray(),
|
|
|
+ EncryptionAlgorithmsClientToServer = ConnectionInfo.Encryptions.Keys.ToArray(),
|
|
|
+ EncryptionAlgorithmsServerToClient = ConnectionInfo.Encryptions.Keys.ToArray(),
|
|
|
+ MacAlgorithmsClientToServer = ConnectionInfo.HmacAlgorithms.Keys.ToArray(),
|
|
|
+ MacAlgorithmsServerToClient = ConnectionInfo.HmacAlgorithms.Keys.ToArray(),
|
|
|
+ CompressionAlgorithmsClientToServer = ConnectionInfo.CompressionAlgorithms.Keys.ToArray(),
|
|
|
+ CompressionAlgorithmsServerToClient = ConnectionInfo.CompressionAlgorithms.Keys.ToArray(),
|
|
|
+ LanguagesClientToServer = new[] {string.Empty},
|
|
|
+ LanguagesServerToClient = new[] {string.Empty},
|
|
|
+ FirstKexPacketFollows = false,
|
|
|
+ Reserved = 0
|
|
|
+ };
|
|
|
}
|
|
|
return _clientInitMessage;
|
|
|
}
|
|
|
@@ -697,7 +697,7 @@ namespace Renci.SshNet
|
|
|
/// </remarks>
|
|
|
public void Disconnect()
|
|
|
{
|
|
|
- DiagnosticAbstraction.Log(string.Format("[{0}] {1} Disconnecting session", ToHex(SessionId), DateTime.Now.Ticks));
|
|
|
+ DiagnosticAbstraction.Log(string.Format("[{0}] Disconnecting session.", ToHex(SessionId)));
|
|
|
|
|
|
// send SSH_MSG_DISCONNECT message, clear socket read buffer and dispose it
|
|
|
Disconnect(DisconnectReason.ByApplication, "Connection terminated by the client.");
|
|
|
@@ -798,11 +798,11 @@ namespace Renci.SshNet
|
|
|
throw new ArgumentNullException("waitHandle");
|
|
|
|
|
|
var waitHandles = new[]
|
|
|
- {
|
|
|
- _exceptionWaitHandle,
|
|
|
- _messageListenerCompleted,
|
|
|
- waitHandle
|
|
|
- };
|
|
|
+ {
|
|
|
+ _exceptionWaitHandle,
|
|
|
+ _messageListenerCompleted,
|
|
|
+ waitHandle
|
|
|
+ };
|
|
|
|
|
|
switch (WaitHandle.WaitAny(waitHandles, timeout))
|
|
|
{
|
|
|
@@ -834,7 +834,7 @@ namespace Renci.SshNet
|
|
|
/// <exception cref="InvalidOperationException">The size of the packet exceeds the maximum size defined by the protocol.</exception>
|
|
|
internal void SendMessage(Message message)
|
|
|
{
|
|
|
- if (_socket == null || !_socket.CanWrite())
|
|
|
+ if (!_socket.CanWrite())
|
|
|
throw new SshConnectionException("Client not connected.");
|
|
|
|
|
|
if (_keyExchangeInProgress && !(message is IKeyExchangedAllowed))
|
|
|
@@ -843,7 +843,7 @@ namespace Renci.SshNet
|
|
|
WaitOnHandle(_keyExchangeCompletedWaitHandle);
|
|
|
}
|
|
|
|
|
|
- DiagnosticAbstraction.Log(string.Format("[{0}] SendMessage to server '{1}': '{2}'.", ToHex(SessionId), message.GetType().Name, message));
|
|
|
+ DiagnosticAbstraction.Log(string.Format("[{0}] Sending message '{1}' to server: '{2}'.", ToHex(SessionId), message.GetType().Name, message));
|
|
|
|
|
|
var paddingMultiplier = _clientCipher == null ? (byte) 8 : Math.Max((byte) 8, _serverCipher.MinimumSize);
|
|
|
var packetData = message.GetPacket(paddingMultiplier, _clientCompression);
|
|
|
@@ -852,9 +852,6 @@ namespace Renci.SshNet
|
|
|
// atomically, and only after the packet has actually been sent
|
|
|
lock (_socketWriteLock)
|
|
|
{
|
|
|
- if (!_socket.IsConnected())
|
|
|
- throw new SshConnectionException("Client not connected.");
|
|
|
-
|
|
|
byte[] hash = null;
|
|
|
var packetDataOffset = 4; // first four bytes are reserved for outbound packet sequence
|
|
|
|
|
|
@@ -881,19 +878,18 @@ namespace Renci.SshNet
|
|
|
var packetLength = packetData.Length - packetDataOffset;
|
|
|
if (hash == null)
|
|
|
{
|
|
|
- SocketAbstraction.Send(_socket, packetData, packetDataOffset, packetLength);
|
|
|
+ SendPacket(packetData, packetDataOffset, packetLength);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
var data = new byte[packetLength + (_clientMac.HashSize/8)];
|
|
|
Buffer.BlockCopy(packetData, packetDataOffset, data, 0, packetLength);
|
|
|
Buffer.BlockCopy(hash, 0, data, packetLength, hash.Length);
|
|
|
-
|
|
|
- SocketAbstraction.Send(_socket, data, 0, data.Length);
|
|
|
+ SendPacket(data, 0, data.Length);
|
|
|
}
|
|
|
|
|
|
// increment the packet sequence number only after we're sure the packet has
|
|
|
- // been sent; even though it's only used for the MAC, it need to be incremented
|
|
|
+ // been sent; even though it's only used for the MAC, it needs to be incremented
|
|
|
// for each package sent.
|
|
|
//
|
|
|
// the server will use it to verify the data integrity, and as such the order in
|
|
|
@@ -902,6 +898,34 @@ namespace Renci.SshNet
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ /// <summary>
|
|
|
+ /// Sends an SSH packet to the server.
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="packet">A byte array containing the packet to send.</param>
|
|
|
+ /// <param name="offset">The offset of the packet.</param>
|
|
|
+ /// <param name="length">The length of the packet.</param>
|
|
|
+ /// <exception cref="SshConnectionException">Client is not connected to the server.</exception>
|
|
|
+ /// <remarks>
|
|
|
+ /// <para>
|
|
|
+ /// The send is performed in a dispose lock to avoid <see cref="NullReferenceException"/>
|
|
|
+ /// and/or <see cref="ObjectDisposedException"/> when sending the packet.
|
|
|
+ /// </para>
|
|
|
+ /// <para>
|
|
|
+ /// This method is only to be used when the connection is established, as the locking
|
|
|
+ /// overhead is not required while establising the connection.
|
|
|
+ /// </para>
|
|
|
+ /// </remarks>
|
|
|
+ private void SendPacket(byte[] packet, int offset, int length)
|
|
|
+ {
|
|
|
+ lock (_socketDisposeLock)
|
|
|
+ {
|
|
|
+ if (!_socket.IsConnected())
|
|
|
+ throw new SshConnectionException("Client not connected.");
|
|
|
+
|
|
|
+ SocketAbstraction.Send(_socket, packet, offset, length);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
/// <summary>
|
|
|
/// Sends a message to the server.
|
|
|
/// </summary>
|
|
|
@@ -923,12 +947,12 @@ namespace Renci.SshNet
|
|
|
}
|
|
|
catch (SshException ex)
|
|
|
{
|
|
|
- DiagnosticAbstraction.Log(string.Format("Failure sending message server '{0}': '{1}' => {2}", message.GetType().Name, message, ex));
|
|
|
+ DiagnosticAbstraction.Log(string.Format("Failure sending message '{0}' to server: '{1}' => {2}", message.GetType().Name, message, ex));
|
|
|
return false;
|
|
|
}
|
|
|
catch (SocketException ex)
|
|
|
{
|
|
|
- DiagnosticAbstraction.Log(string.Format("Failure sending message server '{0}': '{1}' => {2}", message.GetType().Name, message, ex));
|
|
|
+ DiagnosticAbstraction.Log(string.Format("Failure sending message '{0}' to server: '{1}' => {2}", message.GetType().Name, message, ex));
|
|
|
return false;
|
|
|
}
|
|
|
}
|
|
|
@@ -974,16 +998,9 @@ namespace Renci.SshNet
|
|
|
return null;
|
|
|
}
|
|
|
|
|
|
-#if DEBUG_GERT
|
|
|
- DiagnosticAbstraction.Log(string.Format("[{0}] FirstBlock [{1}]: {2}", ToHex(SessionId), blockSize, ToHex(firstBlock)));
|
|
|
-#endif // DEBUG_GERT
|
|
|
-
|
|
|
if (_serverCipher != null)
|
|
|
{
|
|
|
firstBlock = _serverCipher.Decrypt(firstBlock);
|
|
|
-#if DEBUG_GERT
|
|
|
- DiagnosticAbstraction.Log(string.Format("[{0}] FirstBlock decrypted [{1}]: {2}", ToHex(SessionId), firstBlock.Length, ToHex(firstBlock)));
|
|
|
-#endif // DEBUG_GERT
|
|
|
}
|
|
|
|
|
|
packetLength = (uint) (firstBlock[0] << 24 | firstBlock[1] << 16 | firstBlock[2] << 8 | firstBlock[3]);
|
|
|
@@ -1029,16 +1046,8 @@ namespace Renci.SshNet
|
|
|
var numberOfBytesToDecrypt = data.Length - (blockSize + inboundPacketSequenceLength + serverMacLength);
|
|
|
if (numberOfBytesToDecrypt > 0)
|
|
|
{
|
|
|
-#if DEBUG_GERT
|
|
|
- DiagnosticAbstraction.Log(string.Format("[{0}] NextBlocks [{1}]: {2}", ToHex(SessionId), bytesToRead, ToHex(nextBlocks)));
|
|
|
-#endif // DEBUG_GERT
|
|
|
-
|
|
|
var decryptedData = _serverCipher.Decrypt(data, blockSize + inboundPacketSequenceLength, numberOfBytesToDecrypt);
|
|
|
Buffer.BlockCopy(decryptedData, 0, data, blockSize + inboundPacketSequenceLength, decryptedData.Length);
|
|
|
-
|
|
|
-#if DEBUG_GERT
|
|
|
- DiagnosticAbstraction.Log(string.Format("[{0}] NextBlocks decrypted [{1}]: {2}", ToHex(SessionId), decryptedData.Length, ToHex(decryptedData)));
|
|
|
-#endif // DEBUG_GERT
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -1068,10 +1077,6 @@ namespace Renci.SshNet
|
|
|
messagePayloadLength = data.Length;
|
|
|
}
|
|
|
|
|
|
-#if DEBUG_GERT
|
|
|
- DiagnosticAbstraction.Log(string.Format("[{0}] Message info (Sequence:{1},MessagePayloadLength:{2})", ToHex(SessionId), _inboundPacketSequence, messagePayloadLength));
|
|
|
-#endif // DEBUG_GERT
|
|
|
-
|
|
|
_inboundPacketSequence++;
|
|
|
|
|
|
return LoadMessage(data, messagePayloadOffset, messagePayloadLength);
|
|
|
@@ -1096,7 +1101,7 @@ namespace Renci.SshNet
|
|
|
/// <param name="message"><see cref="DisconnectMessage"/> message.</param>
|
|
|
internal void OnDisconnectReceived(DisconnectMessage message)
|
|
|
{
|
|
|
- DiagnosticAbstraction.Log(string.Format("[{0}] {1} Disconnect received: {2} {3}", ToHex(SessionId), DateTime.Now.Ticks, message.ReasonCode, message.Description));
|
|
|
+ DiagnosticAbstraction.Log(string.Format("[{0}] Disconnect received: {1} {2}.", ToHex(SessionId), message.ReasonCode, message.Description));
|
|
|
|
|
|
// transition to disconnecting state to avoid throwing exceptions while cleaning up, and to
|
|
|
// ensure any exceptions that are raised do not overwrite the SshConnectionException that we
|
|
|
@@ -1554,14 +1559,9 @@ namespace Renci.SshNet
|
|
|
var messageType = data[offset];
|
|
|
|
|
|
var message = _sshMessageFactory.Create(messageType);
|
|
|
-
|
|
|
-#if DEBUG_GERT
|
|
|
- DiagnosticAbstraction.Log(string.Format("[{0}] Loading message with offset '{1}': {2}", ToHex(SessionId), offset, ToHex(data, 0)));
|
|
|
-#endif // DEBUG_GERT
|
|
|
-
|
|
|
message.Load(data, offset + 1, count - 1);
|
|
|
|
|
|
- DiagnosticAbstraction.Log(string.Format("[{0}] ReceiveMessage from server: '{1}': '{2}'.", ToHex(SessionId), message.GetType().Name, message));
|
|
|
+ DiagnosticAbstraction.Log(string.Format("[{0}] Received message '{1}' from server: '{2}'.", ToHex(SessionId), message.GetType().Name, message));
|
|
|
|
|
|
return message;
|
|
|
}
|
|
|
@@ -1603,7 +1603,7 @@ namespace Renci.SshNet
|
|
|
var ipAddress = DnsAbstraction.GetHostAddresses(host)[0];
|
|
|
var ep = new IPEndPoint(ipAddress, port);
|
|
|
|
|
|
- DiagnosticAbstraction.Log(string.Format("Initiating connect to '{0}:{1}'.", host, port));
|
|
|
+ DiagnosticAbstraction.Log(string.Format("Initiating connection to '{0}:{1}'.", host, port));
|
|
|
|
|
|
_socket = SocketAbstraction.Connect(ep, ConnectionInfo.Timeout);
|
|
|
|
|
|
@@ -2185,7 +2185,7 @@ namespace Renci.SshNet
|
|
|
{
|
|
|
var connectionException = exp as SshConnectionException;
|
|
|
|
|
|
- DiagnosticAbstraction.Log(string.Format("[{0}] {1} Raised exception: {2}", ToHex(SessionId), DateTime.Now.Ticks, exp));
|
|
|
+ DiagnosticAbstraction.Log(string.Format("[{0}] Raised exception: {1}", ToHex(SessionId), exp));
|
|
|
|
|
|
if (_isDisconnecting)
|
|
|
{
|
|
|
@@ -2210,7 +2210,7 @@ namespace Renci.SshNet
|
|
|
|
|
|
if (connectionException != null)
|
|
|
{
|
|
|
- DiagnosticAbstraction.Log(string.Format("[{0}] {1} Disconnecting after exception: {2}", ToHex(SessionId), DateTime.Now.Ticks, exp));
|
|
|
+ DiagnosticAbstraction.Log(string.Format("[{0}] Disconnecting after exception: {1}", ToHex(SessionId), exp));
|
|
|
Disconnect(connectionException.DisconnectReason, exp.ToString());
|
|
|
}
|
|
|
}
|
|
|
@@ -2266,7 +2266,7 @@ namespace Renci.SshNet
|
|
|
|
|
|
if (disposing)
|
|
|
{
|
|
|
- DiagnosticAbstraction.Log(string.Format("[{0}] Disposing session", ToHex(SessionId)));
|
|
|
+ DiagnosticAbstraction.Log(string.Format("[{0}] Disposing session.", ToHex(SessionId)));
|
|
|
|
|
|
Disconnect();
|
|
|
|