/// <summary> /// Disconnect the SSH transport protocol. /// </summary> /// <param name="disconnectReason">A descriptive reason for the disconnection.</param> /// <param name="reason">The SSH reason code.</param> public void Disconnect(String disconnectReason, DisconnectionReason reason) { try { this.disconnectReason = disconnectReason; SSHPacket packet = GetSSHPacket(true); packet.WriteByte(SSH_MSG_DISCONNECT); packet.WriteUINT32((int)reason); packet.WriteString(disconnectReason); packet.WriteString(""); #if DEBUG System.Diagnostics.Trace.WriteLine("Sending SSH_MSG_DISCONNECT"); System.Diagnostics.Trace.WriteLine(disconnectReason); #endif SendMessage(packet); } catch { } finally { InternalDisconnect(); } }
internal void SendChannelData(byte[] buf, int offset, int len) { try { if (state != CHANNEL_OPEN) { throw new SSHException("The channel is closed", SSHException.CHANNEL_FAILURE); } if (len > 0) { SSHPacket packet = connection.GetPacket(); packet.WriteByte((System.Byte)SSH_MSG_CHANNEL_DATA); packet.WriteUINT32(remoteid); packet.WriteBinaryString(buf, offset, len); #if DEBUG System.Diagnostics.Trace.WriteLine("Sending SSH_MSG_CHANNEL_DATA"); System.Diagnostics.Trace.WriteLine("Channelid=" + ChannelID); #endif connection.SendMessage(packet); } } catch (System.IO.IOException ex) { throw new SSHException(ex.Message, SSHException.INTERNAL_ERROR); } }
/// <summary> /// Close down the output side of the stream. /// </summary> /// <remarks> /// This method sends an SSH_MSG_CHANNEL_EOF message to the remote side. /// </remarks> public override void CloseOutput() { if (!channel.IsClosed && !outputEOF && !channel.closing && !channel.remoteClosed) { SSHPacket packet = channel.connection.GetPacket(); packet.WriteByte(SSH_MSG_CHANNEL_EOF); packet.WriteUINT32(channel.remoteid); try { #if DEBUG System.Diagnostics.Trace.WriteLine("Sending SSH_MSG_CHANNEL_EOF"); System.Diagnostics.Trace.WriteLine("Channelid=" + channel.ChannelID); #endif channel.connection.SendMessage(packet); } finally { outputEOF = true; channel.FireEvent(channel, ChannelState.LOCAL_EOF); } } outputEOF = true; }
internal void AdjustWindow(int increment) { try { SSHPacket packet = connection.GetPacket(); packet.WriteByte((System.Byte)SSH_MSG_WINDOW_ADJUST); packet.WriteUINT32(remoteid); packet.WriteUINT32(increment); localwindow.adjust(increment); #if DEBUG System.Diagnostics.Trace.WriteLine("Sending SSH_MSG_WINDOW_ADJUST"); System.Diagnostics.Trace.WriteLine("Channelid=" + ChannelID); #endif connection.SendMessage(packet); } catch (System.IO.IOException ex) { throw new SSHException(ex.Message, SSHException.INTERNAL_ERROR); } }
/// <summary> /// Sends a close message to the remote side without waiting for a reply /// </summary> public override void SendAsyncClose() { bool performClose = false; lock (this) { if (!closing) { performClose = closing = true; } } if (state == CHANNEL_OPEN && performClose) { try { // Close the ChannelOutputStream stream.Close(); // Send our close message SSHPacket packet = connection.GetPacket(); packet.WriteByte((System.Byte)SSH_MSG_CHANNEL_CLOSE); packet.WriteUINT32(remoteid); try { #if DEBUG System.Diagnostics.Trace.WriteLine("Sending SSH_MSG_CHANNEL_CLOSE"); System.Diagnostics.Trace.WriteLine("Channelid=" + ChannelID); #endif connection.SendMessage(packet); } catch (SSHException) { } } catch (System.IO.EndOfStreamException) { // Ignore this is the message store informing of close/eof } catch (System.IO.IOException ex) { // IO Error during close so the connection has dropped connection.SignalClosingState(); connection.transport.Disconnect("IOException during channel close: " + ex.Message, DisconnectionReason.CONNECTION_LOST); } } }
internal void SendKeyExchangeInit() { try { FireStateChange(TransportProtocolState.PERFORMING_KEYEXCHANGE); numIncomingBytesSinceKEX = 0; numIncomingSSHPacketsSinceKEX = 0; numOutgoingBytesSinceKEX = 0; numOutgoingSSHPacketsSinceKEX = 0; currentState = TransportProtocolState.PERFORMING_KEYEXCHANGE; SSHPacket packet = GetSSHPacket(true); SSH2Context transportContext = (SSH2Context)client.Context; byte[] cookie = new byte[16]; rnd.GetBytes(cookie); packet.WriteByte((byte)SSH_MSG_KEX_INIT); packet.WriteBytes(cookie); packet.WriteString("diffie-hellman-group1-sha1"); packet.WriteString(transportContext.SupportedPublicKeys.List(transportContext.PreferredPublicKey)); packet.WriteString(transportContext.SupportedCiphers.List(transportContext.PreferredCipherCS)); packet.WriteString(transportContext.SupportedCiphers.List(transportContext.PreferredCipherSC)); packet.WriteString(transportContext.SupportedMACs.List(transportContext.PreferredMacCS)); packet.WriteString(transportContext.SupportedMACs.List(transportContext.PreferredMacSC)); packet.WriteString("none"); packet.WriteString("none"); packet.WriteString(""); packet.WriteString(""); packet.WriteByte((byte)0); packet.WriteUINT32(0); #if DEBUG System.Diagnostics.Trace.WriteLine("Sending SSH_MSG_KEX_INIT"); #endif localkex = SendMessage(packet, true); } catch (System.IO.IOException ex) { throw new SSHException(ex.Message, SSHException.INTERNAL_ERROR); } }
/// <summary> /// Sends a channel request. Many channels have extensions that are specific to that particular /// channel type, an example of which is requesting a pseudo terminal from an interactive session. /// </summary> /// <param name="requesttype">the name of the request, for example "pty-req"</param> /// <param name="wantreply">specifies whether the remote side should send a success/failure message</param> /// <param name="requestdata">the request data</param> /// <returns></returns> public bool SendRequest(System.String requesttype, bool wantreply, byte[] requestdata) { lock (this) { try { SSHPacket packet = connection.GetPacket(); packet.WriteByte((System.Byte)SSH_MSG_CHANNEL_REQUEST); packet.WriteUINT32(remoteid); packet.WriteString(requesttype); packet.WriteBool(wantreply); if (requestdata != null) { packet.WriteBytes(requestdata); } #if DEBUG System.Diagnostics.Trace.WriteLine("Sending SSH_MSG_CHANNEL_REQUEST " + requesttype); System.Diagnostics.Trace.WriteLine("Channelid=" + ChannelID); #endif connection.SendMessage(packet); bool result = false; if (wantreply) { packet = ProcessMessages(CHANNEL_REQUEST_MESSAGES); return(packet.MessageID == SSH_MSG_CHANNEL_SUCCESS); } return(result); } catch (System.IO.IOException ex) { throw new SSHException(ex.Message, SSHException.INTERNAL_ERROR); } } }
/// <summary> /// Send a message to the remote side of the connection. /// </summary> /// <param name="packet"></param> /// <param name="returnPayload">Return the unecrypted payload of this packet.</param> public byte[] SendMessage(SSHPacket packet, bool returnPayload) { byte[] payload = null; lock (this) { if (currentState == TransportProtocolState.PERFORMING_KEYEXCHANGE && !IsTransportMessage(packet.MessageID)) { lock (kexqueue) { kexqueue.Add(packet); return(payload); } } try { int padding = 4; // Compress the payload if necersary /*if (outgoingCompression != null) * { * msgdata = outgoingCompression.compress(msgdata, 0, msgdata.Length); * }*/ // Determine the padding length padding += ((outgoingCipherLength - ((packet.Length + padding) % outgoingCipherLength)) % outgoingCipherLength); packet.MoveToPosition(0); // Write the packet length field packet.WriteUINT32(packet.Length - 4 + padding); // Write the padding length packet.WriteByte((byte)padding); // Now skip back up to the end of the packet packet.MoveToEnd(); if (returnPayload) { payload = packet.Payload; } // Create some random data for the padding byte[] pad = new byte[padding]; rnd.GetBytes(pad); packet.WriteBytes(pad); // Generate the MAC if (outgoingMac != null) { outgoingMac.Generate(outgoingSequence, packet.Array, 0, packet.Length, packet.Array, packet.Length); } // Perfrom encrpytion if (encryption != null) { encryption.Transform(packet.Array, 0, packet.Array, 0, packet.Length); } packet.Skip(outgoingMacLength); outgoingBytes += packet.Length; // Send! packet.WriteToStream(transport.GetStream()); outgoingSequence++; numOutgoingBytesSinceKEX += (uint)packet.Length; numOutgoingSSHPacketsSinceKEX++; ReleaseSSHPacket(packet); if (outgoingSequence > 4294967295) { outgoingSequence = 0; } if (numOutgoingBytesSinceKEX >= MAX_NUM_BYTES_BEFORE_REKEY || numOutgoingSSHPacketsSinceKEX >= MAX_NUM_PACKETS_BEFORE_REKEY) { SendKeyExchangeInit(); } } catch (System.IO.IOException ex) { InternalDisconnect(); throw new SSHException("Unexpected termination: " + ex.Message, SSHException.UNEXPECTED_TERMINATION); } catch (System.ObjectDisposedException ex) { InternalDisconnect(); throw new SSHException("Unexpected terminaton: " + ex.Message, SSHException.UNEXPECTED_TERMINATION); } } return(payload); }
/// <summary> /// Process a channel open request. /// </summary> /// <param name="type"></param> /// <param name="remoteid"></param> /// <param name="remotewindow"></param> /// <param name="remotepacket"></param> /// <param name="requestdata"></param> internal void ProcessChannelOpenRequest(System.String type, int remoteid, int remotewindow, int remotepacket, byte[] requestdata) { try { SSHPacket packet = GetPacket(); if (channelfactories.ContainsKey(type)) { try { SSH2Channel channel = ((ChannelFactory)channelfactories[type]).CreateChannel(type, requestdata); // Allocate a channel int localid = AllocateChannel(channel); if (localid > -1) { try { channel.Init(this, localid); byte[] responsedata = channel.Create(); packet.WriteByte(SSH_MSG_CHANNEL_OPEN_CONFIRMATION); packet.WriteUINT32(remoteid); packet.WriteUINT32(localid); packet.WriteUINT32(channel.WindowSize); packet.WriteUINT32(channel.PacketSize); if (responsedata != null) { packet.WriteBytes(requestdata); } #if DEBUG System.Diagnostics.Trace.WriteLine("Sending SSH_MSG_CHANNEL_OPEN_CONFIRMATION"); System.Diagnostics.Trace.WriteLine("Channelid=" + localid); System.Diagnostics.Trace.WriteLine("Remoteid=" + remoteid); #endif transport.SendMessage(packet); channel.Open(remoteid, remotewindow, remotepacket); return; } catch (SSHException ex) { #if DEBUG System.Diagnostics.Trace.WriteLine("Exception occured whilst opening channel"); System.Diagnostics.Trace.WriteLine(ex.StackTrace); #endif packet.WriteByte(SSH_MSG_CHANNEL_OPEN_FAILURE); packet.WriteUINT32(remoteid); packet.WriteUINT32(ChannelOpenException.CONNECT_FAILED); packet.WriteString(ex.Message); packet.WriteString(""); } } else { #if DEBUG System.Diagnostics.Trace.WriteLine("Maximum allowable open channel limit of " + MaximumNumChannels + " exceeded!"); #endif packet.WriteByte(SSH_MSG_CHANNEL_OPEN_FAILURE); packet.WriteUINT32(remoteid); packet.WriteUINT32(ChannelOpenException.RESOURCE_SHORTAGE); packet.WriteString("Maximum allowable open channel limit of " + MaximumNumChannels + " exceeded!"); packet.WriteString(""); } } catch (ChannelOpenException ex) { #if DEBUG System.Diagnostics.Trace.WriteLine("Channel open exception occured whilst opening channel"); System.Diagnostics.Trace.WriteLine(ex.StackTrace); #endif packet.WriteByte(SSH_MSG_CHANNEL_OPEN_FAILURE); packet.WriteUINT32(remoteid); packet.WriteUINT32(ex.Reason); packet.WriteString(ex.Message); packet.WriteString(""); } } else { #if DEBUG System.Diagnostics.Trace.WriteLine(type + " is not a supported channel type"); #endif packet.WriteByte(SSH_MSG_CHANNEL_OPEN_FAILURE); packet.WriteUINT32(remoteid); packet.WriteUINT32(ChannelOpenException.UNKNOWN_CHANNEL_TYPE); packet.WriteString(type + " is not a supported channel type!"); packet.WriteString(""); } #if DEBUG System.Diagnostics.Trace.WriteLine("Sending SSH_MSG_CHANNEL_OPEN_FAILURE"); System.Diagnostics.Trace.WriteLine("Remoteid=" + remoteid); System.Diagnostics.Trace.WriteLine("Name=" + type); #endif transport.SendMessage(packet); } catch (System.IO.IOException ex1) { throw new SSHException(ex1.Message, SSHException.INTERNAL_ERROR); } }
/// <summary> /// Opens a channel /// </summary> /// <param name="channel"></param> /// <param name="requestdata"></param> public void OpenChannel(SSH2Channel channel, byte[] requestdata) { lock (this) { try { int channelid = AllocateChannel(channel); if (channelid == -1) { throw new ChannelOpenException("Maximum number of channels exceeded", ChannelOpenException.RESOURCE_SHORTAGE); } channel.Init(this, channelid); SSHPacket packet = GetPacket(); packet.WriteByte(SSH_MSG_CHANNEL_OPEN); packet.WriteString(channel.Name); packet.WriteUINT32(channel.ChannelID); packet.WriteUINT32(channel.WindowSize); packet.WriteUINT32(channel.PacketSize); if (requestdata != null) { packet.WriteBytes(requestdata); } #if DEBUG System.Diagnostics.Trace.WriteLine("Sending SSH_MSG_CHANNEL_OPEN"); System.Diagnostics.Trace.WriteLine("Channelid=" + channel.ChannelID); System.Diagnostics.Trace.WriteLine("Name=" + channel.Name); #endif transport.SendMessage(packet); packet = channel.MessageStore.NextMessage(CHANNEL_OPEN_RESPONSE_MESSAGES); #if DEBUG System.Diagnostics.Trace.WriteLine("Received reply to SSH_MSG_CHANNEL_OPEN"); channel.LogMessage(packet); #endif if (packet.MessageID == SSH_MSG_CHANNEL_OPEN_FAILURE) { FreeChannel(channel); int reason = (int)packet.ReadUINT32(); throw new ChannelOpenException(packet.ReadString(), reason); } else { int remoteid = (int)packet.ReadUINT32(); int remotewindow = (int)packet.ReadUINT32(); int remotepacket = (int)packet.ReadUINT32(); byte[] responsedata = new byte[packet.Available]; packet.ReadBytes(responsedata); channel.Open(remoteid, remotewindow, remotepacket, responsedata); return; } } catch (System.IO.IOException ex) { throw new SSHException(ex.Message, SSHException.INTERNAL_ERROR); } } }