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

📄 ssh2connection.cs

📁 Granados是一个基于.NET的SSH客户端库。同时支持SSH1和SSH2。实现了AES, Blowfish, TripleDES, RSA, DSA等加密验证算法。实现TCP协议连接。
💻 CS
📖 第 1 页 / 共 3 页
字号:
/* ---------------------------------------------------------------------------
 *
 * Copyright (c) Routrek Networks, Inc.    All Rights Reserved..
 * 
 * This file is a part of the Granados SSH Client Library that is subject to
 * the license included in the distributed package.
 * You may not use this file except in compliance with the license.
 * 
 * ---------------------------------------------------------------------------
 */
using System;
using System.Collections;
using System.IO;
using System.Threading;
using System.Diagnostics;
using System.Net.Sockets;
using System.Text;
using System.Security.Cryptography;

using Routrek.PKI;
using Routrek.SSHC;
using Routrek.Toolkit;

namespace Routrek.SSHCV2
{
	public sealed class SSH2Connection : SSHConnection {
	
		//packet count for transmission and reception
		private int _tSequence;

		//MAC for transmission and reception
		private MAC _tMAC;
		private SSH2PacketBuilder _packetBuilder;

		//server info
		private SSH2ConnectionInfo _cInfo;

		private bool _waitingForPortForwardingResponse;

		private KeyExchanger _asyncKeyExchanger;

		public SSH2Connection(SSHConnectionParameter param, ISSHConnectionEventReceiver r, string serverversion, string clientversion) : base(param, r) {
			_cInfo = new SSH2ConnectionInfo();
			_cInfo._serverVersionString = serverversion;
			_cInfo._clientVersionString = clientversion;
			
			_packetBuilder = new SSH2PacketBuilder(new SynchronizedSSH2PacketHandler());
		}
		internal override IByteArrayHandler PacketBuilder {
			get {
				return _packetBuilder;
			}
		}
		public override SSHConnectionInfo ConnectionInfo {
			get {
				return _cInfo;
			}
		}

		internal override AuthenticationResult Connect(AbstractSocket s) {
			_stream = s;
			
			KeyExchanger kex = new KeyExchanger(this, null);
			if(!kex.SynchronousKexExchange()) {
				_stream.Close();
				return AuthenticationResult.Failure;
			}
			//Step3 user authentication
			ServiceRequest("ssh-userauth");
			_authenticationResult = UserAuth();
			return _authenticationResult;
		}


		private void ServiceRequest(string servicename) {
			SSH2DataWriter wr = new SSH2DataWriter();
			wr.WritePacketType(PacketType.SSH_MSG_SERVICE_REQUEST);
			wr.Write(servicename);
			TransmitPacket(wr.ToByteArray());

			byte[] response = ReceivePacket().Data;
			SSH2DataReader re = new SSH2DataReader(response);
			PacketType t = re.ReadPacketType();
			if(t!=PacketType.SSH_MSG_SERVICE_ACCEPT) {
				throw new SSHException("service establishment failed "+t);
			}

			string s = Encoding.ASCII.GetString(re.ReadString());
			if(servicename!=s)
				throw new SSHException("protocol error");
		}

		private AuthenticationResult UserAuth() {
			string sn = "ssh-connection"; 

			SSH2DataWriter wr = new SSH2DataWriter();
			wr.WritePacketType(PacketType.SSH_MSG_USERAUTH_REQUEST);
			wr.Write(_param.UserName);
			if(_param.AuthenticationType==AuthenticationType.Password) {
				//Password authentication
				wr.Write(sn); 
				wr.Write("password");
				wr.Write(false);
				wr.Write(_param.Password);
			}
			else if(_param.AuthenticationType==AuthenticationType.KeyboardInteractive) {
				wr.Write(sn); 
				wr.Write("keyboard-interactive");
				wr.Write(""); //lang
				wr.Write(""); //submethod
			}
			else {
				//public key authentication
				SSH2UserAuthKey kp = SSH2UserAuthKey.FromSECSHStyleFile(_param.IdentityFile, _param.Password);
				SSH2DataWriter signsource = new SSH2DataWriter();
				signsource.WriteAsString(_sessionID);
				signsource.WritePacketType(PacketType.SSH_MSG_USERAUTH_REQUEST);
				signsource.Write(_param.UserName);
				signsource.Write(sn);
				signsource.Write("publickey");
				signsource.Write(true);
				signsource.Write(SSH2Util.PublicKeyAlgorithmName(kp.Algorithm));
				signsource.WriteAsString(kp.GetPublicKeyBlob());

				SSH2DataWriter signpack = new SSH2DataWriter();
				signpack.Write(SSH2Util.PublicKeyAlgorithmName(kp.Algorithm));
				signpack.WriteAsString(kp.Sign(signsource.ToByteArray()));

				wr.Write(sn);
				wr.Write("publickey");
				wr.Write(true);
				wr.Write(SSH2Util.PublicKeyAlgorithmName(kp.Algorithm));
				wr.WriteAsString(kp.GetPublicKeyBlob());
				wr.WriteAsString(signpack.ToByteArray());
			}
			TransmitPacket(wr.ToByteArray());

			_authenticationResult = ProcessAuthenticationResponse();
			if(_authenticationResult==AuthenticationResult.Failure)
				throw new SSHException(Strings.GetString("AuthenticationFailed"));
			return _authenticationResult;
		}
		private AuthenticationResult ProcessAuthenticationResponse() {
			do {
				SSH2DataReader response = new SSH2DataReader(ReceivePacket().Data);
				PacketType h = response.ReadPacketType();
				if(h==PacketType.SSH_MSG_USERAUTH_FAILURE) {
					string msg = Encoding.ASCII.GetString(response.ReadString());
					return AuthenticationResult.Failure;
				}
				else if(h==PacketType.SSH_MSG_USERAUTH_BANNER) {
					Debug.WriteLine("USERAUTH_BANNER");
				}
				else if(h==PacketType.SSH_MSG_USERAUTH_SUCCESS) {
					_packetBuilder.Handler = new CallbackSSH2PacketHandler(this);
					return AuthenticationResult.Success; //successfully exit
				}
				else if(h==PacketType.SSH_MSG_USERAUTH_INFO_REQUEST) {
					string name = Encoding.ASCII.GetString(response.ReadString());
					string inst = Encoding.ASCII.GetString(response.ReadString());
					string lang = Encoding.ASCII.GetString(response.ReadString());
					int num = response.ReadInt32();
					string[] prompts = new string[num];
					for(int i=0; i<num; i++) {
						prompts[i] = Encoding.ASCII.GetString(response.ReadString());
						bool echo = response.ReadBool();
					}
					_eventReceiver.OnAuthenticationPrompt(prompts);
					return AuthenticationResult.Prompt;
				}
				else
					throw new SSHException("protocol error: unexpected packet type "+h);
			} while(true);
		}
		public AuthenticationResult DoKeyboardInteractiveAuth(string[] input) {
			if(_param.AuthenticationType!=AuthenticationType.KeyboardInteractive)
				throw new SSHException("DoKeyboardInteractiveAuth() must be called with keyboard-interactive authentication");
			SSH2DataWriter re = new SSH2DataWriter();
			re.WritePacketType(PacketType.SSH_MSG_USERAUTH_INFO_RESPONSE);
			re.Write(input.Length);
			foreach(string t in input)
				re.Write(t);
			TransmitPacket(re.ToByteArray());

			_authenticationResult = ProcessAuthenticationResponse();
			//try again on failure
			if(_authenticationResult==AuthenticationResult.Failure) {
				SSH2DataWriter wr = new SSH2DataWriter();
				wr.WritePacketType(PacketType.SSH_MSG_USERAUTH_REQUEST);
				wr.Write(_param.UserName);
				wr.Write("ssh-connection"); 
				wr.Write("keyboard-interactive");
				wr.Write(""); //lang
				wr.Write(""); //submethod
				TransmitPacket(wr.ToByteArray());
				_authenticationResult = ProcessAuthenticationResponse();
			}
			return _authenticationResult;
		}
		
		public override SSHChannel OpenShell(ISSHChannelEventReceiver receiver) {
			//open channel
			SSH2DataWriter wr = new SSH2DataWriter();
			wr.WritePacketType(PacketType.SSH_MSG_CHANNEL_OPEN);
			wr.Write("session");
			int local_channel = this.RegisterChannelEventReceiver(null, receiver)._localID;

			wr.Write(local_channel);
			wr.Write(_param.WindowSize); //initial window size
			int windowsize = _param.WindowSize;
			wr.Write(_param.MaxPacketSize); //max packet size
			SSH2Channel channel = new SSH2Channel(this, ChannelType.Shell, local_channel);
			TransmitPacket(wr.ToByteArray());
			
			return channel;
		}

		public override SSHChannel ForwardPort(ISSHChannelEventReceiver receiver, string remote_host, int remote_port, string originator_host, int originator_port) {
			SSH2DataWriter wr = new SSH2DataWriter();
			wr.WritePacketType(PacketType.SSH_MSG_CHANNEL_OPEN);
			wr.Write("direct-tcpip");
			int local_id = RegisterChannelEventReceiver(null, receiver)._localID;
			wr.Write(local_id);
			wr.Write(_param.WindowSize); //initial window size
			int windowsize = _param.WindowSize;
			wr.Write(_param.MaxPacketSize); //max packet size
			wr.Write(remote_host);
			wr.Write(remote_port);
			wr.Write(originator_host);
			wr.Write(originator_port);

			SSH2Channel channel = new SSH2Channel(this, ChannelType.ForwardedLocalToRemote, local_id);
			
			TransmitPacket(wr.ToByteArray());
			
			return channel;
		}

		public override void ListenForwardedPort(string allowed_host, int bind_port) {
			SSH2DataWriter wr = new SSH2DataWriter();
			wr.WritePacketType(PacketType.SSH_MSG_GLOBAL_REQUEST);
			wr.Write("tcpip-forward");
			wr.Write(true);
			wr.Write(allowed_host);
			wr.Write(bind_port);

			_waitingForPortForwardingResponse = true;
			TransmitPacket(wr.ToByteArray());
		}

		public override void CancelForwardedPort(string host, int port) {
			SSH2DataWriter wr = new SSH2DataWriter();
			wr.WritePacketType(PacketType.SSH_MSG_GLOBAL_REQUEST);
			wr.Write("cancel-tcpip-forward");
			wr.Write(true);
			wr.Write(host);
			wr.Write(port);
			TransmitPacket(wr.ToByteArray());
		}

		private void ProcessPortforwardingRequest(ISSHConnectionEventReceiver receiver, SSH2DataReader reader) {
			string method = Encoding.ASCII.GetString(reader.ReadString());

			int remote_channel = reader.ReadInt32();
			int window_size = reader.ReadInt32(); //skip initial window size
			int servermaxpacketsize = reader.ReadInt32();
			string host = Encoding.ASCII.GetString(reader.ReadString());
			int port = reader.ReadInt32();
			string originator_ip = Encoding.ASCII.GetString(reader.ReadString());
			int originator_port = reader.ReadInt32();
			
			PortForwardingCheckResult r = receiver.CheckPortForwardingRequest(host,port,originator_ip,originator_port);
			SSH2DataWriter wr = new SSH2DataWriter();
			if(r.allowed) {
				//send OPEN_CONFIRMATION
				SSH2Channel channel = new SSH2Channel(this, ChannelType.ForwardedRemoteToLocal, RegisterChannelEventReceiver(null, r.channel)._localID, remote_channel, servermaxpacketsize);
				wr.WritePacketType(PacketType.SSH_MSG_CHANNEL_OPEN_CONFIRMATION);
				wr.Write(remote_channel);
				wr.Write(channel.LocalChannelID);
				wr.Write(_param.WindowSize); //initial window size
				wr.Write(_param.MaxPacketSize); //max packet size
				receiver.EstablishPortforwarding(r.channel, channel);
			}
			else {
				wr.WritePacketType(PacketType.SSH_MSG_CHANNEL_OPEN_FAILURE);
				wr.Write(remote_channel);
				wr.Write(r.reason_code);
				wr.Write(r.reason_message);
				wr.Write(""); //lang tag
			}
			TransmitPacket(wr.ToByteArray());
		}

		internal SSH2Packet TransmitPacket(byte[] payload) {
			lock(_tLockObject) { 
				SSH2Packet p = SSH2Packet.FromPlainPayload(payload, _tCipher==null? 8 : _tCipher.BlockSize, _param.Random);
				if(_tMAC!=null) p.CalcHash(_tMAC, _tSequence);

				_tSequence++;
				p.WriteTo(_stream, _tCipher);
				return p;
			}
		}

		//synchronous reception
		internal SSH2Packet ReceivePacket() {

			while(true) {
				SSH2Packet p = null;
				SynchronizedSSH2PacketHandler handler = (SynchronizedSSH2PacketHandler)_packetBuilder.Handler;
				if(!handler.HasPacket) {
					handler.Wait();
					if(handler.State==ReceiverState.Error)
						throw new SSHException(handler.ErrorMessage);
					else if(handler.State==ReceiverState.Closed)
						throw new SSHException("socket closed");
				}
				p = handler.PopPacket();

				SSH2DataReader r = new SSH2DataReader(p.Data);
				PacketType pt = r.ReadPacketType();
				if(pt==PacketType.SSH_MSG_IGNORE) {
					if(_eventReceiver!=null) _eventReceiver.OnIgnoreMessage(r.ReadString());
				}
				else if(pt==PacketType.SSH_MSG_DEBUG) {
					bool f = r.ReadBool();
					if(_eventReceiver!=null) _eventReceiver.OnDebugMessage(f, r.ReadString());
				}
				else
					return p;
			}
		}
		internal void AsyncReceivePacket(SSH2Packet packet) {
			try {
				ProcessPacket(packet);
			}
			catch(Exception ex) {
				//Debug.WriteLine(ex.StackTrace);
				if(!_closed)
					_eventReceiver.OnError(ex, ex.Message);
			}
		}

		private bool ProcessPacket(SSH2Packet packet) {
			//Debug.WriteLine("ProcessPacket pt="+pt);
			SSH2DataReader r = new SSH2DataReader(packet.Data);
			PacketType pt = r.ReadPacketType();

			if(pt==PacketType.SSH_MSG_DISCONNECT) {
				int errorcode = r.ReadInt32();
				//string description = Encoding.ASCII.GetString(r.ReadString());
				_eventReceiver.OnConnectionClosed();
				return false;
			}
			else if(_waitingForPortForwardingResponse) {
				if(pt!=PacketType.SSH_MSG_REQUEST_SUCCESS)
					_eventReceiver.OnUnknownMessage((byte)pt, r.Image);
				_waitingForPortForwardingResponse = false;
				return true;
			}
			else if(pt==PacketType.SSH_MSG_CHANNEL_OPEN) {
				ProcessPortforwardingRequest(_eventReceiver, r);
				return true;
			}
			else if(pt>=PacketType.SSH_MSG_CHANNEL_OPEN_CONFIRMATION && pt<=PacketType.SSH_MSG_CHANNEL_FAILURE) {

⌨️ 快捷键说明

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