⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ssh2connection.cs

📁 Granados是一个基于.NET的SSH客户端库。同时支持SSH1和SSH2。实现了AES, Blowfish, TripleDES, RSA, DSA等加密验证算法。实现TCP协议连接。
💻 CS
📖 第 1 页 / 共 3 页
字号:
				int local_channel = r.ReadInt32();
				ChannelEntry e = FindChannelEntry(local_channel);
				if(e!=null) //throw new SSHException("Unknown channel "+local_channel);
					((SSH2Channel)e._channel).ProcessPacket(e._receiver, pt, 5+r.Rest, r);
				else
					Debug.WriteLine("unexpected channel pt="+pt+" local_channel="+local_channel.ToString());
				return true;
			}
			else if(pt==PacketType.SSH_MSG_IGNORE) {
				_eventReceiver.OnIgnoreMessage(r.ReadString());
				return true;
			}
			else if(_asyncKeyExchanger!=null) {
				_asyncKeyExchanger.AsyncProcessPacket(packet);
				return true;
			}
			else if(pt==PacketType.SSH_MSG_KEXINIT) {
				Debug.WriteLine("Host sent KEXINIT");
				_asyncKeyExchanger = new KeyExchanger(this, _sessionID);
				_asyncKeyExchanger.AsyncProcessPacket(packet);
				return true;
			}
			else {
				_eventReceiver.OnUnknownMessage((byte)pt, r.Image);
				return false;
			}
		}

		public override void Disconnect(string msg) {
			if(_closed) return;
			SSH2DataWriter wr = new SSH2DataWriter();
			wr.WritePacketType(PacketType.SSH_MSG_DISCONNECT);
			wr.Write(0);
			wr.Write(msg);
			wr.Write(""); //language
			TransmitPacket(wr.ToByteArray());
			_stream.Flush();
			_closed = true;
			_stream.Close();
		}

		public override void Close() {
			if(_closed) return;
			_closed = true;
			_stream.Close();
		} 
		public override void SendIgnorableData(string msg) {
			SSH2DataWriter w = new SSH2DataWriter();
			w.WritePacketType(PacketType.SSH_MSG_IGNORE);
			w.Write(msg);
			TransmitPacket(w.ToByteArray());
		}
		public void ReexchangeKeys() {
			_asyncKeyExchanger = new KeyExchanger(this, _sessionID);
			_asyncKeyExchanger.AsyncStartReexchange();
		}

		internal void LockCommunication() {
			_packetBuilder.SetSignal(false);
		}
		internal void UnlockCommunication() {
			_packetBuilder.SetSignal(true);
		}
		internal void RefreshKeys(byte[] sessionID, Cipher tc, Cipher rc, MAC tm, MAC rm) {
			_sessionID = sessionID;
			_tCipher = tc;
			_tMAC = tm;
			_packetBuilder.SetCipher(rc, _param.CheckMACError? rm : null);
			_asyncKeyExchanger = null;
		}

	}

	public class SSH2Channel : SSHChannel {
		//channel property
		protected int _windowSize;
		protected int _leftWindowSize;
		protected int _serverMaxPacketSize;

		//negotiation status
		protected int _negotiationStatus;

		public SSH2Channel(SSHConnection con, ChannelType type, int local_id) : base(con, type, local_id) {
			_windowSize = _leftWindowSize = con.Param.WindowSize;
			_negotiationStatus = type==ChannelType.Shell? 3 : type==ChannelType.ForwardedLocalToRemote? 1 : type==ChannelType.Session? 1 : 0;
		}
		public SSH2Channel(SSHConnection con, ChannelType type, int local_id, int remote_id, int maxpacketsize) : base(con, type, local_id) {
			_windowSize = _leftWindowSize = con.Param.WindowSize;
			Debug.Assert(type==ChannelType.ForwardedRemoteToLocal);
			_remoteID = remote_id;
			_serverMaxPacketSize = maxpacketsize;
			_negotiationStatus = 0;
		}

		public override void ResizeTerminal(int width, int height, int pixel_width, int pixel_height) {
			SSH2DataWriter wr = new SSH2DataWriter();
			wr.WritePacketType(PacketType.SSH_MSG_CHANNEL_REQUEST);
			wr.Write(_remoteID);
			wr.Write("window-change");
			wr.Write(false);
			wr.Write(width);
			wr.Write(height);
			wr.Write(pixel_width); //no graphics
			wr.Write(pixel_height);
			TransmitPacket(wr.ToByteArray());
		}
		public override void Transmit(byte[] data)	{
			//!!it is better idea that we wait a WINDOW_ADJUST if the left size is lack
			SSH2DataWriter wr = new SSH2DataWriter();
			wr.WritePacketType(PacketType.SSH_MSG_CHANNEL_DATA);
			wr.Write(_remoteID);
			wr.WriteAsString(data);

			TransmitPacket(wr.ToByteArray());
		}
		public override void Transmit(byte[] data, int offset, int length)	{
			SSH2DataWriter wr = new SSH2DataWriter();
			wr.WritePacketType(PacketType.SSH_MSG_CHANNEL_DATA);
			wr.Write(_remoteID);
			wr.WriteAsString(data, offset, length);

			TransmitPacket(wr.ToByteArray());
		}

		public override void SendEOF() {
			if(_connection.IsClosed) return;
			SSH2DataWriter wr = new SSH2DataWriter();
			wr.WritePacketType(PacketType.SSH_MSG_CHANNEL_EOF);
			wr.Write(_remoteID);
			TransmitPacket(wr.ToByteArray());
		}


		public override void Close() {
			if(_connection.IsClosed) return;
			SSH2DataWriter wr = new SSH2DataWriter();
			wr.WritePacketType(PacketType.SSH_MSG_CHANNEL_CLOSE);
			wr.Write(_remoteID);
			TransmitPacket(wr.ToByteArray());

		}

		//maybe this is SSH2 only feature
		public void SetEnvironmentVariable(string name, string value) {
			SSH2DataWriter wr = new SSH2DataWriter();
			wr.WritePacketType(PacketType.SSH_MSG_CHANNEL_REQUEST);
			wr.Write(_remoteID);
			wr.Write("env");
			wr.Write(false);
			wr.Write(name);
			wr.Write(value);
			TransmitPacket(wr.ToByteArray());
		}
		public void SendBreak(int time) {
			SSH2DataWriter wr = new SSH2DataWriter();
			wr.WritePacketType(PacketType.SSH_MSG_CHANNEL_REQUEST);
			wr.Write(_remoteID);
			wr.Write("break");
			wr.Write(true);
			wr.Write(time);
			TransmitPacket(wr.ToByteArray());
		}

		internal void ProcessPacket(ISSHChannelEventReceiver receiver, PacketType pt, int data_length, SSH2DataReader re) {

			//NOTE: the offset of 're' is next to 'receipiant channel' field
			_leftWindowSize -= data_length;
			while(_leftWindowSize <= _windowSize) {
				SSH2DataWriter adj = new SSH2DataWriter();
				adj.WritePacketType(PacketType.SSH_MSG_CHANNEL_WINDOW_ADJUST);
				adj.Write(_remoteID);
				adj.Write(_windowSize);
				TransmitPacket(adj.ToByteArray());
				_leftWindowSize += _windowSize;
				//Debug.WriteLine("Window size is adjusted to " + _leftWindowSize);
			}

			if(pt==PacketType.SSH_MSG_CHANNEL_WINDOW_ADJUST) {
				int w = re.ReadInt32();
				//Debug.WriteLine(String.Format("Window Adjust +={0}",w));
			}
			else if(_negotiationStatus!=0) { //when the negotiation is not completed
				if(_type==ChannelType.Shell)
					OpenShell(receiver, pt, re);
				else if(_type==ChannelType.ForwardedLocalToRemote)
					ReceivePortForwardingResponse(receiver, pt, re);
				else if(_type==ChannelType.Session)
					EstablishSession(receiver, pt, re);
			}
			else {
				switch(pt) {
					case PacketType.SSH_MSG_CHANNEL_DATA: {
						int len = re.ReadInt32();
						receiver.OnData(re.Image, re.Offset, len);
					}
						break;
					case PacketType.SSH_MSG_CHANNEL_EXTENDED_DATA: {
						int t = re.ReadInt32();
						byte[] data = re.ReadString();
						receiver.OnExtendedData(t, data);
					}
						break;
					case PacketType.SSH_MSG_CHANNEL_REQUEST: {
						string request = Encoding.ASCII.GetString(re.ReadString());
						bool reply = re.ReadBool();
						if(request=="exit-status") {
							int status = re.ReadInt32();
						}
					}
						break;
					case PacketType.SSH_MSG_CHANNEL_EOF:
						receiver.OnChannelEOF();
						break;
					case PacketType.SSH_MSG_CHANNEL_CLOSE:
						_connection.UnregisterChannelEventReceiver(_localID);
						receiver.OnChannelClosed();
						break;
					case PacketType.SSH_MSG_CHANNEL_FAILURE:
					case PacketType.SSH_MSG_CHANNEL_SUCCESS:
						receiver.OnMiscPacket((byte)pt, re.Image, re.Offset, re.Rest);
						break;
					default:
						receiver.OnMiscPacket((byte)pt, re.Image, re.Offset, re.Rest);
						Debug.WriteLine("Unknown Packet "+pt);
						break;
				}			

			}

		}

		private void TransmitPacket(byte[] data) {
			((SSH2Connection)_connection).TransmitPacket(data);
		}

		private void OpenShell(ISSHChannelEventReceiver receiver, PacketType pt, SSH2DataReader reader) {
			if(_negotiationStatus==3) {
				if(pt!=PacketType.SSH_MSG_CHANNEL_OPEN_CONFIRMATION) {
					if(pt!=PacketType.SSH_MSG_CHANNEL_OPEN_FAILURE)
						receiver.OnChannelError(null, "opening channel failed; packet type="+pt);
					else {
						int errcode = reader.ReadInt32();
						string msg = Encoding.ASCII.GetString(reader.ReadString());
						receiver.OnChannelError(null, msg);
					}
					Close();
				}
				else {
					_remoteID = reader.ReadInt32();
					_serverMaxPacketSize = reader.ReadInt32();
				
					//open pty
					SSH2DataWriter wr = new SSH2DataWriter();
					wr.WritePacketType(PacketType.SSH_MSG_CHANNEL_REQUEST);
					wr.Write(_remoteID);
					wr.Write("pty-req");
					wr.Write(true);
					wr.Write(_connection.Param.TerminalName);
					wr.Write(_connection.Param.TerminalWidth);
					wr.Write(_connection.Param.TerminalHeight);
					wr.Write(_connection.Param.TerminalPixelWidth);
					wr.Write(_connection.Param.TerminalPixelHeight);
					wr.WriteAsString(new byte[0]);
					TransmitPacket(wr.ToByteArray());

					_negotiationStatus = 2;
				}
			}
			else if(_negotiationStatus==2) {
				if(pt!=PacketType.SSH_MSG_CHANNEL_SUCCESS) {
					receiver.OnChannelError(null, "opening pty failed");
					Close();
				}
				else {
					//open shell
					SSH2DataWriter wr = new SSH2DataWriter();
					wr.Write((byte)PacketType.SSH_MSG_CHANNEL_REQUEST);
					wr.Write(_remoteID);
					wr.Write("shell");
					wr.Write(true);
					TransmitPacket(wr.ToByteArray());

					_negotiationStatus = 1;
				}
			}
			else if(_negotiationStatus==1) {
				if(pt!=PacketType.SSH_MSG_CHANNEL_SUCCESS) {
					receiver.OnChannelError(null, "Opening shell failed: packet type="+pt.ToString());
					Close();
				}
				else {
					receiver.OnChannelReady();
					_negotiationStatus = 0; //goal!
				}
			}
			else
				Debug.Assert(false);
		}

		private void ReceivePortForwardingResponse(ISSHChannelEventReceiver receiver, PacketType pt, SSH2DataReader reader) {
			if(_negotiationStatus==1) {
				if(pt!=PacketType.SSH_MSG_CHANNEL_OPEN_CONFIRMATION) {
					if(pt!=PacketType.SSH_MSG_CHANNEL_OPEN_FAILURE)
						receiver.OnChannelError(null, "opening channel failed; packet type="+pt);
					else {
						int errcode = reader.ReadInt32();
						string msg = Encoding.ASCII.GetString(reader.ReadString());
						receiver.OnChannelError(null, msg);
					}
					Close();
				}
				else {
					_remoteID = reader.ReadInt32();
					_serverMaxPacketSize = reader.ReadInt32();
					_negotiationStatus = 0;
					receiver.OnChannelReady();
				}
			}
			else
				Debug.Assert(false);
		}
		private void EstablishSession(ISSHChannelEventReceiver receiver, PacketType pt, SSH2DataReader reader) {
			if(_negotiationStatus==1) {
				if(pt!=PacketType.SSH_MSG_CHANNEL_OPEN_CONFIRMATION) {
					if(pt!=PacketType.SSH_MSG_CHANNEL_OPEN_FAILURE)
						receiver.OnChannelError(null, "opening channel failed; packet type="+pt);
					else {
						int remote_id = reader.ReadInt32();
						int errcode = reader.ReadInt32();
						string msg = Encoding.ASCII.GetString(reader.ReadString());
						receiver.OnChannelError(null, msg);
					}
					Close();
				}
				else {
					_remoteID = reader.ReadInt32();
					_serverMaxPacketSize = reader.ReadInt32();
					_negotiationStatus = 0;
					receiver.OnChannelReady();
				}
			}
			else
				Debug.Assert(false);
		}
	}

	internal class KeyExchanger {
		private SSH2Connection _con;
		private SSHConnectionParameter _param;
		private SSH2ConnectionInfo _cInfo;
		//payload of KEXINIT message
		private byte[] _serverKEXINITPayload;
		private byte[] _clientKEXINITPayload;

		//true if the host sent KEXINIT first
		private bool _startedByHost;

		private ManualResetEvent _newKeyEvent;

		//status
		private enum Status {
			INITIAL,
			WAIT_KEXINIT,
			WAIT_KEXDH_REPLY,
			WAIT_NEWKEYS,

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -