?? ssh2connection.cs
字號:
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 + -