Просмотр исходного кода

任何消息解析错误把Session删除,断开连接,防止客户端伪造消息

tanghai 7 лет назад
Родитель
Сommit
04d7e366d6

+ 17 - 5
Server/Hotfix/Module/Message/InnerMessageDispatcher.cs

@@ -7,9 +7,21 @@ namespace ETHotfix
 	{
 		public void Dispatch(Session session, Packet packet)
 		{
-			ushort opcode = packet.Opcode;
-			Type messageType = Game.Scene.GetComponent<OpcodeTypeComponent>().GetType(opcode);
-			IMessage message = (IMessage)session.Network.MessagePacker.DeserializeFrom(messageType, packet.Bytes, Packet.Index, packet.Length - Packet.Index);
+			IMessage message;
+			try
+			{
+				Type messageType = Game.Scene.GetComponent<OpcodeTypeComponent>().GetType(packet.Opcode);
+				message = (IMessage)session.Network.MessagePacker.DeserializeFrom(messageType, packet.Bytes, Packet.Index, packet.Length - Packet.Index);
+			}
+			catch (Exception e)
+			{
+				// 出现任何解析消息异常都要断开Session,防止客户端伪造消息
+				Log.Error(e);
+				session.Error = ErrorCode.ERR_PacketParserError;
+				session.Network.Remove(session.Id);
+				return;
+			}
+			
 			
 			// 收到actor消息,放入actor队列
 			if (message is IActorMessage iActorMessage)
@@ -26,7 +38,7 @@ namespace ETHotfix
 					session.Reply(response);
 					return;
 				}
-
+	
 				MailBoxComponent mailBoxComponent = entity.GetComponent<MailBoxComponent>();
 				if (mailBoxComponent == null)
 				{
@@ -44,7 +56,7 @@ namespace ETHotfix
 				return;
 			}
 			
-			Game.Scene.GetComponent<MessageDispatherComponent>().Handle(session, new MessageInfo(opcode, message));
+			Game.Scene.GetComponent<MessageDispatherComponent>().Handle(session, new MessageInfo(packet.Opcode, message));
 		}
 	}
 }

+ 24 - 18
Server/Hotfix/Module/Message/OuterMessageDispatcher.cs

@@ -7,25 +7,37 @@ namespace ETHotfix
 	{
 		public async void Dispatch(Session session, Packet packet)
 		{
-			ushort opcode = packet.Opcode;
-			Type messageType = session.Network.Entity.GetComponent<OpcodeTypeComponent>().GetType(opcode);
-			object message = session.Network.MessagePacker.DeserializeFrom(messageType, packet.Bytes, Packet.Index, packet.Length - Packet.Index);
-
+			object message;
+			try
+			{
+				Type messageType = session.Network.Entity.GetComponent<OpcodeTypeComponent>().GetType(packet.Opcode);
+				message = session.Network.MessagePacker.DeserializeFrom(messageType, packet.Bytes, Packet.Index, packet.Length - Packet.Index);
+				
+			}
+			catch (Exception e)
+			{
+				// 出现任何异常都要断开Session,防止客户端伪造消息
+				Log.Error(e);
+				session.Error = ErrorCode.ERR_PacketParserError;
+				session.Network.Remove(session.Id);
+				return;
+			}
+			
 			//Log.Debug($"recv: {JsonHelper.ToJson(message)}");
-
+	
 			switch (message)
 			{
 				case IFrameMessage iFrameMessage: // 如果是帧消息,构造成OneFrameMessage发给对应的unit
 				{
 					long unitId = session.GetComponent<SessionPlayerComponent>().Player.UnitId;
 					ActorMessageSender actorMessageSender = Game.Scene.GetComponent<ActorMessageSenderComponent>().Get(unitId);
-
+	
 					// 这里设置了帧消息的id,防止客户端伪造
 					iFrameMessage.Id = unitId;
-
+	
 					OneFrameMessage oneFrameMessage = new OneFrameMessage
 					{
-						Op = opcode,
+						Op = packet.Opcode,
 						AMessage = session.Network.MessagePacker.SerializeToByteArray(iFrameMessage)
 					};
 					actorMessageSender.Send(oneFrameMessage);
@@ -35,11 +47,11 @@ namespace ETHotfix
 				{
 					long unitId = session.GetComponent<SessionPlayerComponent>().Player.UnitId;
 					ActorMessageSender actorMessageSender = Game.Scene.GetComponent<ActorMessageSenderComponent>().Get(unitId);
-
+	
 					int rpcId = iActorRequest.RpcId; // 这里要保存客户端的rpcId
 					IResponse response = await actorMessageSender.Call(iActorRequest);
 					response.RpcId = rpcId;
-
+	
 					session.Reply(response);
 					return;
 				}
@@ -51,14 +63,8 @@ namespace ETHotfix
 					return;
 				}
 			}
-
-			if (message != null)
-			{
-				Game.Scene.GetComponent<MessageDispatherComponent>().Handle(session, new MessageInfo(opcode, message));
-				return;
-			}
-
-			throw new Exception($"message type error: {message.GetType().FullName}");
+	
+			Game.Scene.GetComponent<MessageDispatherComponent>().Handle(session, new MessageInfo(packet.Opcode, message));
 		}
 	}
 }

+ 20 - 9
Unity/Assets/Scripts/Module/Message/ClientDispatcher.cs

@@ -6,17 +6,28 @@ namespace ETModel
 	{
 		public void Dispatch(Session session, Packet packet)
 		{
-			ushort opcode = packet.Opcode;
-			
-			if (OpcodeHelper.IsClientHotfixMessage(opcode))
+			object message;
+			try
 			{
-				session.GetComponent<SessionCallbackComponent>().MessageCallback.Invoke(session, packet);
+				if (OpcodeHelper.IsClientHotfixMessage(packet.Opcode))
+				{
+					session.GetComponent<SessionCallbackComponent>().MessageCallback.Invoke(session, packet);
+					return;
+				}
+
+				OpcodeTypeComponent opcodeTypeComponent = session.Network.Entity.GetComponent<OpcodeTypeComponent>();
+				Type responseType = opcodeTypeComponent.GetType(packet.Opcode);
+				message = session.Network.MessagePacker.DeserializeFrom(responseType, packet.Bytes, Packet.Index, packet.Length - Packet.Index);
+			}
+			catch (Exception e)
+			{
+				// 出现任何解析消息异常都要断开Session,防止客户端伪造消息
+				Log.Error(e);
+				session.Error = ErrorCode.ERR_PacketParserError;
+				session.Network.Remove(session.Id);
 				return;
 			}
-
-			OpcodeTypeComponent opcodeTypeComponent = session.Network.Entity.GetComponent<OpcodeTypeComponent>();
-			Type responseType = opcodeTypeComponent.GetType(opcode);
-			object message = session.Network.MessagePacker.DeserializeFrom(responseType, packet.Bytes, Packet.Index, packet.Length - Packet.Index);
+				
 			// 如果是帧同步消息,交给ClientFrameComponent处理
 			FrameMessage frameMessage = message as FrameMessage;
 			if (frameMessage != null)
@@ -26,7 +37,7 @@ namespace ETModel
 			}
 
 			// 普通消息或者是Rpc请求消息
-			MessageInfo messageInfo = new MessageInfo(opcode, message);
+			MessageInfo messageInfo = new MessageInfo(packet.Opcode, message);
 			Game.Scene.GetComponent<MessageDispatherComponent>().Handle(session, messageInfo);
 		}
 	}

+ 1 - 0
Unity/Assets/Scripts/Module/Message/ErrorCode.cs

@@ -6,6 +6,7 @@ namespace ETModel
 		public const int ERR_NotFoundActor = 2;
 		public const int ERR_ActorNoMailBoxComponent = 3;
 		public const int ERR_ActorTimeOut = 4;
+		public const int ERR_PacketParserError = 5;
 
 		public const int ERR_AccountOrPasswordError = 102;
 		public const int ERR_SessionActorError = 103;

+ 37 - 14
Unity/Assets/Scripts/Module/Message/Network/KCP/KChannel.cs

@@ -202,16 +202,31 @@ namespace ETModel
 				this.recvBuffer.Write(sizeBuffer, 0, sizeBuffer.Length);
 				this.recvBuffer.Write(cacheBytes, 0, count);
 
-				if (this.recvTcs != null)
+				if (this.recvTcs == null)
+				{
+					continue;
+				}
+
+				try
 				{
 					bool isOK = this.parser.Parse();
-					if (isOK)
+					if (!isOK)
 					{
-						Packet pkt = this.parser.GetPacket();
-						var tcs = this.recvTcs;
-						this.recvTcs = null;
-						tcs.SetResult(pkt);
+						continue;
 					}
+
+					Packet packet = this.parser.GetPacket();
+					var tcs = this.recvTcs;
+					this.recvTcs = null;
+					tcs.SetResult(packet);
+				}
+				catch (Exception e)
+				{
+					this.OnError(ErrorCode.ERR_PacketParserError);
+						
+					var tcs = this.recvTcs;
+					this.recvTcs = null;
+					tcs.SetException(e);
 				}
 			}
 		}
@@ -264,18 +279,26 @@ namespace ETModel
 		{
 			if (this.IsDisposed)
 			{
-				throw new Exception("KChannel已经被Dispose, 不能接收消息");
+				throw new Exception("TChannel已经被Dispose, 不能接收消息");
 			}
 
-			bool isOK = this.parser.Parse();
-			if (isOK)
+			try
 			{
-				Packet packet = this.parser.GetPacket();
-				return Task.FromResult(packet);
-			}
+				bool isOK = this.parser.Parse();
+				if (isOK)
+				{
+					Packet packet = this.parser.GetPacket();
+					return Task.FromResult(packet);
+				}
 
-			recvTcs = new TaskCompletionSource<Packet>();
-			return recvTcs.Task;
+				this.recvTcs = new TaskCompletionSource<Packet>();
+				return this.recvTcs.Task;
+			}
+			catch (Exception)
+			{
+				this.OnError(ErrorCode.ERR_PacketParserError);
+				throw;
+			}
 		}
 	}
 }

+ 4 - 4
Unity/Assets/Scripts/Module/Message/Network/TCP/PacketParser.cs

@@ -10,7 +10,8 @@ namespace ETModel
 	
 	public class Packet
 	{
-		public const int MinSize = 2;
+		public const int MinSize = 3;
+		public const int MaxSize = 60000;
 		public const int FlagIndex = 0;
 		public const int OpcodeIndex = 1;
 		public const int Index = 3;
@@ -39,7 +40,6 @@ namespace ETModel
 	internal class PacketParser
 	{
 		private readonly CircularBuffer buffer;
-
 		private ushort packetSize;
 		private ParserState state;
 		private readonly Packet packet = new Packet(ushort.MaxValue);
@@ -71,9 +71,9 @@ namespace ETModel
 						{
 							this.buffer.Read(this.packet.Bytes, 0, 2);
 							this.packetSize = BitConverter.ToUInt16(this.packet.Bytes, 0);
-							if (packetSize > 60000)
+							if (packetSize < Packet.MinSize || packetSize > Packet.MaxSize)
 							{
-								throw new Exception($"packet too large, size: {this.packetSize}");
+								throw new Exception($"packet size error: {this.packetSize}");
 							}
 							this.state = ParserState.PacketBody;
 						}

+ 45 - 23
Unity/Assets/Scripts/Module/Message/Network/TCP/TChannel.cs

@@ -62,8 +62,8 @@ namespace ETModel
 			}
 			catch (Exception e)
 			{
-				this.OnError((int)SocketError.SocketError);
 				Log.Error($"connect error: {ipEndPoint} {e}");
+				this.OnError((int)SocketError.SocketError);
 			}
 		}
 
@@ -76,6 +76,7 @@ namespace ETModel
 			
 			base.Dispose();
 
+			this.recvTcs = null;
 			this.tcpClient.Close();
 		}
 
@@ -122,13 +123,9 @@ namespace ETModel
 
 		private async void StartSend()
 		{
+			long instanceId = this.InstanceId;
 			try
 			{
-				if (this.IsDisposed)
-				{
-					return;
-				}
-
 				// 如果正在发送中,不需要再次发送
 				if (this.isSending)
 				{
@@ -137,7 +134,7 @@ namespace ETModel
 
 				while (true)
 				{
-					if (this.IsDisposed)
+					if (this.InstanceId != instanceId)
 					{
 						return;
 					}
@@ -178,11 +175,12 @@ namespace ETModel
 
 		private async void StartRecv()
 		{
+			long instanceId = this.InstanceId;
 			try
 			{
 				while (true)
 				{
-					if (this.IsDisposed)
+					if (this.InstanceId != instanceId)
 					{
 						return;
 					}
@@ -200,18 +198,34 @@ namespace ETModel
 						this.OnError((int)SocketError.NetworkReset);
 						return;
 					}
-					
-					if (this.recvTcs != null)
+
+					// 如果没有recv调用
+					if (this.recvTcs == null)
+					{
+						continue;
+					}
+
+					try
 					{
 						bool isOK = this.parser.Parse();
-						if (isOK)
+						if (!isOK)
 						{
-							Packet packet = this.parser.GetPacket();
-
-							var tcs = this.recvTcs;
-							this.recvTcs = null;
-							tcs.SetResult(packet);
+							continue;
 						}
+
+						Packet packet = this.parser.GetPacket();
+
+						var tcs = this.recvTcs;
+						this.recvTcs = null;
+						tcs.SetResult(packet);
+					}
+					catch (Exception e)
+					{
+						this.OnError(ErrorCode.ERR_PacketParserError);
+						
+						var tcs = this.recvTcs;
+						this.recvTcs = null;
+						tcs.SetException(e);
 					}
 				}
 			}
@@ -237,15 +251,23 @@ namespace ETModel
 				throw new Exception("TChannel已经被Dispose, 不能接收消息");
 			}
 
-			bool isOK = this.parser.Parse();
-			if (isOK)
+			try
 			{
-				Packet packet = this.parser.GetPacket();
-				return Task.FromResult(packet);
-			}
+				bool isOK = this.parser.Parse();
+				if (isOK)
+				{
+					Packet packet = this.parser.GetPacket();
+					return Task.FromResult(packet);
+				}
 
-			recvTcs = new TaskCompletionSource<Packet>();
-			return recvTcs.Task;
+				this.recvTcs = new TaskCompletionSource<Packet>();
+				return this.recvTcs.Task;
+			}
+			catch (Exception)
+			{
+				this.OnError(ErrorCode.ERR_PacketParserError);
+				throw;
+			}
 		}
 	}
 }

+ 23 - 16
Unity/Assets/Scripts/Module/Message/Session.cs

@@ -95,9 +95,11 @@ namespace ETModel
 
 		private async void StartRecv()
 		{
+			long instanceId = this.InstanceId;
+			
 			while (true)
 			{
-				if (this.IsDisposed)
+				if (this.InstanceId != instanceId)
 				{
 					return;
 				}
@@ -106,8 +108,8 @@ namespace ETModel
 				try
 				{
 					packet = await this.channel.Recv();
-					
-					if (this.IsDisposed)
+
+					if (this.InstanceId != instanceId)
 					{
 						return;
 					}
@@ -115,7 +117,7 @@ namespace ETModel
 				catch (Exception e)
 				{
 					Log.Error(e);
-					continue;
+					return;
 				}
 				
 				try
@@ -131,13 +133,6 @@ namespace ETModel
 
 		private void Run(Packet packet)
 		{
-			if (packet.Length < Packet.MinSize)
-			{
-				Log.Error($"message error length < {Packet.MinSize}, ip: {this.RemoteAddress}");
-				this.Network.Remove(this.Id);
-				return;
-			}
-
 			byte flag = packet.Flag;
 			ushort opcode = packet.Opcode;
 
@@ -155,12 +150,24 @@ namespace ETModel
 				this.Network.MessageDispatcher.Dispatch(this, packet);
 				return;
 			}
-			
-			OpcodeTypeComponent opcodeTypeComponent = this.Network.Entity.GetComponent<OpcodeTypeComponent>();
-			Type responseType = opcodeTypeComponent.GetType(opcode);
-			object message = this.Network.MessagePacker.DeserializeFrom(responseType, packet.Bytes, Packet.Index, packet.Length - Packet.Index);
-			//Log.Debug($"recv: {JsonHelper.ToJson(message)}");
 
+			object message;
+			try
+			{
+				OpcodeTypeComponent opcodeTypeComponent = this.Network.Entity.GetComponent<OpcodeTypeComponent>();
+				Type responseType = opcodeTypeComponent.GetType(opcode);
+				message = this.Network.MessagePacker.DeserializeFrom(responseType, packet.Bytes, Packet.Index, packet.Length - Packet.Index);
+				//Log.Debug($"recv: {JsonHelper.ToJson(message)}");
+			}
+			catch (Exception e)
+			{
+				// 出现任何消息解析异常都要断开Session,防止客户端伪造消息
+				Log.Error(e);
+				this.Error = ErrorCode.ERR_PacketParserError;
+				this.Network.Remove(this.Id);
+				return;
+			}
+				
 			IResponse response = message as IResponse;
 			if (response == null)
 			{