Security implementation
This commit is contained in:
@ -6,8 +6,10 @@ using Lidgren.Network;
|
|||||||
using RageCoop.Core;
|
using RageCoop.Core;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
using System.Security.Cryptography;
|
||||||
using GTA.Math;
|
using GTA.Math;
|
||||||
using GTA.Native;
|
using GTA.Native;
|
||||||
|
using System.Net;
|
||||||
|
|
||||||
namespace RageCoop.Client
|
namespace RageCoop.Client
|
||||||
{
|
{
|
||||||
@ -16,9 +18,10 @@ namespace RageCoop.Client
|
|||||||
public static NetClient Client;
|
public static NetClient Client;
|
||||||
public static float Latency = 0;
|
public static float Latency = 0;
|
||||||
public static bool ShowNetworkInfo = false;
|
public static bool ShowNetworkInfo = false;
|
||||||
|
public static Security Security;
|
||||||
static Networking()
|
static Networking()
|
||||||
{
|
{
|
||||||
|
Security=new Security(Main.Logger);
|
||||||
Task.Run(() =>
|
Task.Run(() =>
|
||||||
{
|
{
|
||||||
while (true)
|
while (true)
|
||||||
@ -36,7 +39,7 @@ namespace RageCoop.Client
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void ToggleConnection(string address)
|
public static void ToggleConnection(string address,string password=null)
|
||||||
{
|
{
|
||||||
if (IsOnServer)
|
if (IsOnServer)
|
||||||
{
|
{
|
||||||
@ -44,6 +47,7 @@ namespace RageCoop.Client
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
password = password ?? Main.Settings.Password;
|
||||||
// 623c92c287cc392406e7aaaac1c0f3b0 = RAGECOOP
|
// 623c92c287cc392406e7aaaac1c0f3b0 = RAGECOOP
|
||||||
NetPeerConfiguration config = new NetPeerConfiguration("623c92c287cc392406e7aaaac1c0f3b0")
|
NetPeerConfiguration config = new NetPeerConfiguration("623c92c287cc392406e7aaaac1c0f3b0")
|
||||||
{
|
{
|
||||||
@ -51,6 +55,7 @@ namespace RageCoop.Client
|
|||||||
};
|
};
|
||||||
|
|
||||||
config.EnableMessageType(NetIncomingMessageType.ConnectionLatencyUpdated);
|
config.EnableMessageType(NetIncomingMessageType.ConnectionLatencyUpdated);
|
||||||
|
config.EnableMessageType(NetIncomingMessageType.UnconnectedData);
|
||||||
|
|
||||||
Client = new NetClient(config);
|
Client = new NetClient(config);
|
||||||
Client.Start();
|
Client.Start();
|
||||||
@ -70,17 +75,27 @@ namespace RageCoop.Client
|
|||||||
}
|
}
|
||||||
|
|
||||||
EntityPool.AddPlayer();
|
EntityPool.AddPlayer();
|
||||||
|
Task.Run(() =>
|
||||||
|
{
|
||||||
|
GetServerPublicKey(address);
|
||||||
|
|
||||||
|
|
||||||
// Send HandshakePacket
|
// Send HandshakePacket
|
||||||
NetOutgoingMessage outgoingMessage = Client.CreateMessage();
|
NetOutgoingMessage outgoingMessage = Client.CreateMessage();
|
||||||
new Packets.Handshake()
|
var handshake=new Packets.Handshake()
|
||||||
{
|
{
|
||||||
PedID = Main.LocalPlayerID,
|
PedID = Main.LocalPlayerID,
|
||||||
Username = Main.Settings.Username,
|
Username = Main.Settings.Username,
|
||||||
ModVersion = Main.CurrentVersion,
|
ModVersion = Main.CurrentVersion,
|
||||||
}.Pack(outgoingMessage);
|
PassHashEncrypted=Security.Encrypt(password.GetHash())
|
||||||
|
};
|
||||||
|
Security.GetSymmetricKeysCrypted(out handshake.AesKeyCrypted,out handshake.AesIVCrypted);
|
||||||
|
handshake.Pack(outgoingMessage);
|
||||||
Client.Connect(ip[0], short.Parse(ip[1]), outgoingMessage);
|
Client.Connect(ip[0], short.Parse(ip[1]), outgoingMessage);
|
||||||
|
Main.QueueAction(() => { GTA.UI.Notification.Show($"~y~Trying to connect..."); });
|
||||||
|
|
||||||
|
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public static bool IsOnServer
|
public static bool IsOnServer
|
||||||
@ -111,39 +126,18 @@ namespace RageCoop.Client
|
|||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
private static void DecodeNativeCallWithResponse(Packets.NativeResponse packet)
|
|
||||||
{
|
|
||||||
object result = DecodeNativeCall(packet.Hash, packet.Args, true, packet.ResultType);
|
|
||||||
|
|
||||||
if (Main.CheckNativeHash.ContainsKey(packet.Hash))
|
|
||||||
{
|
|
||||||
foreach (KeyValuePair<ulong, byte> hash in Main.CheckNativeHash)
|
|
||||||
{
|
|
||||||
if (hash.Key == packet.Hash)
|
|
||||||
{
|
|
||||||
lock (Main.ServerItems)
|
|
||||||
{
|
|
||||||
Main.ServerItems.Add((int)result, hash.Value);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
NetOutgoingMessage outgoingMessage = Client.CreateMessage();
|
|
||||||
new Packets.NativeResponse()
|
|
||||||
{
|
|
||||||
Hash = 0,
|
|
||||||
Args = new List<object>() { result },
|
|
||||||
ID = packet.ID
|
|
||||||
}.Pack(outgoingMessage);
|
|
||||||
Client.SendMessage(outgoingMessage, NetDeliveryMethod.ReliableOrdered, (byte)ConnectionChannel.Native);
|
|
||||||
Client.FlushSendQueue();
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
#endregion // -- PLAYER --
|
#endregion // -- PLAYER --
|
||||||
|
|
||||||
|
private static void GetServerPublicKey(string address,int timeout=10000)
|
||||||
|
{
|
||||||
|
var msg=Client.CreateMessage();
|
||||||
|
new Packets.PublicKeyRequest().Pack(msg);
|
||||||
|
|
||||||
|
var adds =address.Split(':');
|
||||||
|
Client.SendUnconnectedMessage(msg,adds[0],int.Parse(adds[1]));
|
||||||
|
PublicKeyReceived.WaitOne(timeout);
|
||||||
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -6,13 +6,16 @@ using Lidgren.Network;
|
|||||||
using RageCoop.Core;
|
using RageCoop.Core;
|
||||||
using GTA;
|
using GTA;
|
||||||
using RageCoop.Client.Menus;
|
using RageCoop.Client.Menus;
|
||||||
|
using System.Threading;
|
||||||
using GTA.Math;
|
using GTA.Math;
|
||||||
using GTA.Native;
|
using GTA.Native;
|
||||||
|
using System.Net;
|
||||||
|
|
||||||
namespace RageCoop.Client
|
namespace RageCoop.Client
|
||||||
{
|
{
|
||||||
internal static partial class Networking
|
internal static partial class Networking
|
||||||
{
|
{
|
||||||
|
private static AutoResetEvent PublicKeyReceived=new AutoResetEvent(false);
|
||||||
public static void ProcessMessage(NetIncomingMessage message)
|
public static void ProcessMessage(NetIncomingMessage message)
|
||||||
{
|
{
|
||||||
if(message == null) { return; }
|
if(message == null) { return; }
|
||||||
@ -30,25 +33,8 @@ namespace RageCoop.Client
|
|||||||
#if !NON_INTERACTIVE
|
#if !NON_INTERACTIVE
|
||||||
CoopMenu.InitiateConnectionMenuSetting();
|
CoopMenu.InitiateConnectionMenuSetting();
|
||||||
#endif
|
#endif
|
||||||
Main.QueueAction(() => { GTA.UI.Notification.Show("~y~Trying to connect..."); return true; });
|
|
||||||
break;
|
break;
|
||||||
case NetConnectionStatus.Connected:
|
case NetConnectionStatus.Connected:
|
||||||
if (message.SenderConnection.RemoteHailMessage.ReadByte() != (byte)PacketTypes.Handshake)
|
|
||||||
{
|
|
||||||
Client.Disconnect("Wrong packet!");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
int len = message.SenderConnection.RemoteHailMessage.ReadInt32();
|
|
||||||
byte[] data = message.SenderConnection.RemoteHailMessage.ReadBytes(len);
|
|
||||||
|
|
||||||
Packets.Handshake handshakePacket = new Packets.Handshake();
|
|
||||||
handshakePacket.Unpack(data);
|
|
||||||
|
|
||||||
#if !NON_INTERACTIVE
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
Main.QueueAction(() => {
|
Main.QueueAction(() => {
|
||||||
CoopMenu.ConnectedMenuSetting();
|
CoopMenu.ConnectedMenuSetting();
|
||||||
Main.MainChat.Init();
|
Main.MainChat.Init();
|
||||||
@ -57,7 +43,6 @@ namespace RageCoop.Client
|
|||||||
});
|
});
|
||||||
|
|
||||||
Main.Logger.Info(">> Connected <<");
|
Main.Logger.Info(">> Connected <<");
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case NetConnectionStatus.Disconnected:
|
case NetConnectionStatus.Disconnected:
|
||||||
DownloadManager.Cleanup();
|
DownloadManager.Cleanup();
|
||||||
@ -89,21 +74,17 @@ namespace RageCoop.Client
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case NetIncomingMessageType.Data:
|
case NetIncomingMessageType.Data:
|
||||||
if (message.LengthBytes==0) { break; }
|
|
||||||
|
|
||||||
var packetType = (PacketTypes)message.ReadByte();
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
|
|
||||||
|
if (message.LengthBytes==0) { break; }
|
||||||
|
var packetType = PacketTypes.Unknown;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
packetType = (PacketTypes)message.ReadByte();
|
||||||
int len = message.ReadInt32();
|
int len = message.ReadInt32();
|
||||||
byte[] data = message.ReadBytes(len);
|
byte[] data = message.ReadBytes(len);
|
||||||
switch (packetType)
|
switch (packetType)
|
||||||
{
|
{
|
||||||
case PacketTypes.CleanUpWorld:
|
|
||||||
{
|
|
||||||
Main.QueueAction(() => { Main.CleanUpWorld(); return true; });
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case PacketTypes.PlayerConnect:
|
case PacketTypes.PlayerConnect:
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -241,9 +222,25 @@ namespace RageCoop.Client
|
|||||||
Client.Disconnect($"Packet Error [{packetType}]");
|
Client.Disconnect($"Packet Error [{packetType}]");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case NetIncomingMessageType.ConnectionLatencyUpdated:
|
case NetIncomingMessageType.ConnectionLatencyUpdated:
|
||||||
Latency = message.ReadFloat();
|
Latency = message.ReadFloat();
|
||||||
break;
|
break;
|
||||||
|
case NetIncomingMessageType.UnconnectedData:
|
||||||
|
{
|
||||||
|
var packetType = (PacketTypes)message.ReadByte();
|
||||||
|
int len = message.ReadInt32();
|
||||||
|
byte[] data = message.ReadBytes(len);
|
||||||
|
if (packetType==PacketTypes.PublicKeyResponse)
|
||||||
|
{
|
||||||
|
var packet=new Packets.PublicKeyResponse();
|
||||||
|
packet.Unpack(data);
|
||||||
|
Security.SetServerPublicKey(packet.Modulus,packet.Exponent);
|
||||||
|
PublicKeyReceived.Set();
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
case NetIncomingMessageType.DebugMessage:
|
case NetIncomingMessageType.DebugMessage:
|
||||||
case NetIncomingMessageType.ErrorMessage:
|
case NetIncomingMessageType.ErrorMessage:
|
||||||
case NetIncomingMessageType.WarningMessage:
|
case NetIncomingMessageType.WarningMessage:
|
||||||
|
@ -16,6 +16,7 @@ namespace RageCoop.Client.Scripting
|
|||||||
{
|
{
|
||||||
API.RegisterCustomEventHandler(CustomEvents.SetAutoRespawn,SetAutoRespawn);
|
API.RegisterCustomEventHandler(CustomEvents.SetAutoRespawn,SetAutoRespawn);
|
||||||
API.RegisterCustomEventHandler(CustomEvents.NativeCall,NativeCall);
|
API.RegisterCustomEventHandler(CustomEvents.NativeCall,NativeCall);
|
||||||
|
API.RegisterCustomEventHandler(CustomEvents.CleanUpWorld, (s) => Main.QueueAction(() => Main.CleanUpWorld()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void OnStop()
|
public override void OnStop()
|
||||||
|
40
RageCoop.Client/Security.cs
Normal file
40
RageCoop.Client/Security.cs
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
using System.IO;
|
||||||
|
using RageCoop.Core;
|
||||||
|
namespace RageCoop.Client
|
||||||
|
{
|
||||||
|
internal class Security
|
||||||
|
{
|
||||||
|
public RSA ServerRSA { get; set; }
|
||||||
|
public Aes ClientAes { get; set; }=Aes.Create();
|
||||||
|
private Logger Logger;
|
||||||
|
public Security(Logger logger)
|
||||||
|
{
|
||||||
|
Logger = logger;
|
||||||
|
ClientAes.GenerateKey();
|
||||||
|
ClientAes.GenerateIV();
|
||||||
|
}
|
||||||
|
public void GetSymmetricKeysCrypted(out byte[] cryptedKey,out byte[] cryptedIV)
|
||||||
|
{
|
||||||
|
// Logger?.Debug($"Aes.Key:{ClientAes.Key.Dump()}, Aes.IV:{ClientAes.IV.Dump()}");
|
||||||
|
cryptedKey =ServerRSA.Encrypt(ClientAes.Key, RSAEncryptionPadding.Pkcs1);
|
||||||
|
cryptedIV =ServerRSA.Encrypt(ClientAes.IV,RSAEncryptionPadding.Pkcs1);
|
||||||
|
}
|
||||||
|
public byte[] Encrypt(byte[] data)
|
||||||
|
{
|
||||||
|
return new CryptoStream(new MemoryStream(data), ClientAes.CreateEncryptor(), CryptoStreamMode.Read).ReadToEnd();
|
||||||
|
}
|
||||||
|
public void SetServerPublicKey(byte[] modulus,byte[] exponent)
|
||||||
|
{
|
||||||
|
var para = new RSAParameters();
|
||||||
|
para.Modulus = modulus;
|
||||||
|
para.Exponent = exponent;
|
||||||
|
ServerRSA=RSA.Create(para);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -11,6 +11,8 @@ namespace RageCoop.Client
|
|||||||
/// Don't use it!
|
/// Don't use it!
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string Username { get; set; } = "Player";
|
public string Username { get; set; } = "Player";
|
||||||
|
|
||||||
|
public string Password { get; set; } = "";
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Don't use it!
|
/// Don't use it!
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -9,6 +9,7 @@ using GTA.Native;
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Xml.Serialization;
|
using System.Xml.Serialization;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
|
||||||
namespace RageCoop.Client
|
namespace RageCoop.Client
|
||||||
{
|
{
|
||||||
@ -197,6 +198,11 @@ namespace RageCoop.Client
|
|||||||
{
|
{
|
||||||
Function.Call(Hash.SET_RADIO_TO_STATION_INDEX, index);
|
Function.Call(Hash.SET_RADIO_TO_STATION_INDEX, index);
|
||||||
}
|
}
|
||||||
|
public static byte[] GetHash(this string inputString)
|
||||||
|
{
|
||||||
|
using (HashAlgorithm algorithm = SHA256.Create())
|
||||||
|
return algorithm.ComputeHash(Encoding.UTF8.GetBytes(inputString));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -54,7 +54,10 @@ namespace RageCoop.Core
|
|||||||
CurrentIndex += length;
|
CurrentIndex += length;
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
public byte[] ReadByteArray()
|
||||||
|
{
|
||||||
|
return ReadByteArray(ReadInt());
|
||||||
|
}
|
||||||
public short ReadShort()
|
public short ReadShort()
|
||||||
{
|
{
|
||||||
short value = BitConverter.ToInt16(ResultArray, CurrentIndex);
|
short value = BitConverter.ToInt16(ResultArray, CurrentIndex);
|
||||||
|
@ -6,6 +6,7 @@ using System.Threading.Tasks;
|
|||||||
using GTA.Math;
|
using GTA.Math;
|
||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
using System.IO;
|
||||||
namespace RageCoop.Core
|
namespace RageCoop.Core
|
||||||
{
|
{
|
||||||
public class CoreUtils
|
public class CoreUtils
|
||||||
@ -82,6 +83,11 @@ namespace RageCoop.Core
|
|||||||
bytes.AddInt(sb.Length);
|
bytes.AddInt(sb.Length);
|
||||||
bytes.AddRange(sb);
|
bytes.AddRange(sb);
|
||||||
}
|
}
|
||||||
|
public static void AddArray(this List<byte> bytes, byte[] toadd)
|
||||||
|
{
|
||||||
|
bytes.AddInt(toadd.Length);
|
||||||
|
bytes.AddRange(toadd);
|
||||||
|
}
|
||||||
|
|
||||||
public static int GetHash(string s)
|
public static int GetHash(string s)
|
||||||
{
|
{
|
||||||
@ -202,5 +208,28 @@ namespace RageCoop.Core
|
|||||||
action(obj);
|
action(obj);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
public static byte[] ReadToEnd(this Stream stream)
|
||||||
|
{
|
||||||
|
if (stream is MemoryStream)
|
||||||
|
return ((MemoryStream)stream).ToArray();
|
||||||
|
|
||||||
|
using (var memoryStream = new MemoryStream())
|
||||||
|
{
|
||||||
|
stream.CopyTo(memoryStream);
|
||||||
|
return memoryStream.ToArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static byte[] Join(this List<byte[]> arrays)
|
||||||
|
{
|
||||||
|
if (arrays.Count==1) { return arrays[0]; }
|
||||||
|
var output = new byte[arrays.Sum(arr => arr.Length)];
|
||||||
|
int writeIdx = 0;
|
||||||
|
foreach (var byteArr in arrays)
|
||||||
|
{
|
||||||
|
byteArr.CopyTo(output, writeIdx);
|
||||||
|
writeIdx += byteArr.Length;
|
||||||
|
}
|
||||||
|
return output;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,12 +13,14 @@ namespace RageCoop.Core
|
|||||||
PlayerConnect=1,
|
PlayerConnect=1,
|
||||||
PlayerDisconnect=2,
|
PlayerDisconnect=2,
|
||||||
PlayerInfoUpdate=3,
|
PlayerInfoUpdate=3,
|
||||||
|
PublicKeyRequest=4,
|
||||||
|
PublicKeyResponse=5,
|
||||||
|
|
||||||
ChatMessage=10,
|
ChatMessage=10,
|
||||||
// NativeCall=11,
|
// NativeCall=11,
|
||||||
// NativeResponse=12,
|
// NativeResponse=12,
|
||||||
//Mod=13,
|
// Mod=13,
|
||||||
CleanUpWorld=14,
|
// CleanUpWorld=14,
|
||||||
|
|
||||||
FileTransferChunk=15,
|
FileTransferChunk=15,
|
||||||
FileTransferRequest=16,
|
FileTransferRequest=16,
|
||||||
@ -49,6 +51,7 @@ namespace RageCoop.Core
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
Unknown=255
|
||||||
}
|
}
|
||||||
public static class PacketExtensions
|
public static class PacketExtensions
|
||||||
{
|
{
|
||||||
|
@ -16,6 +16,21 @@ namespace RageCoop.Core
|
|||||||
|
|
||||||
public string ModVersion { get; set; }
|
public string ModVersion { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The asymetrically crypted Aes key
|
||||||
|
/// </summary>
|
||||||
|
public byte[] AesKeyCrypted;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The asymetrically crypted Aes IV
|
||||||
|
/// </summary>
|
||||||
|
public byte[] AesIVCrypted;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The password hash with client Aes
|
||||||
|
/// </summary>
|
||||||
|
public byte[] PassHashEncrypted { get; set; }
|
||||||
|
|
||||||
public override void Pack(NetOutgoingMessage message)
|
public override void Pack(NetOutgoingMessage message)
|
||||||
{
|
{
|
||||||
#region PacketToNetOutGoingMessage
|
#region PacketToNetOutGoingMessage
|
||||||
@ -36,6 +51,16 @@ namespace RageCoop.Core
|
|||||||
byteArray.AddRange(BitConverter.GetBytes(modVersionBytes.Length));
|
byteArray.AddRange(BitConverter.GetBytes(modVersionBytes.Length));
|
||||||
byteArray.AddRange(modVersionBytes);
|
byteArray.AddRange(modVersionBytes);
|
||||||
|
|
||||||
|
// Write AesKeyCrypted
|
||||||
|
byteArray.AddArray(AesKeyCrypted);
|
||||||
|
|
||||||
|
// Write AesIVCrypted
|
||||||
|
byteArray.AddArray(AesIVCrypted);
|
||||||
|
|
||||||
|
|
||||||
|
// Write PassHash
|
||||||
|
byteArray.AddArray(PassHashEncrypted);
|
||||||
|
|
||||||
byte[] result = byteArray.ToArray();
|
byte[] result = byteArray.ToArray();
|
||||||
|
|
||||||
message.Write(result.Length);
|
message.Write(result.Length);
|
||||||
@ -52,12 +77,17 @@ namespace RageCoop.Core
|
|||||||
PedID = reader.ReadInt();
|
PedID = reader.ReadInt();
|
||||||
|
|
||||||
// Read Username
|
// Read Username
|
||||||
int usernameLength = reader.ReadInt();
|
Username = reader.ReadString(reader.ReadInt());
|
||||||
Username = reader.ReadString(usernameLength);
|
|
||||||
|
|
||||||
// Read ModVersion
|
// Read ModVersion
|
||||||
int modVersionLength = reader.ReadInt();
|
ModVersion = reader.ReadString(reader.ReadInt());
|
||||||
ModVersion = reader.ReadString(modVersionLength);
|
|
||||||
|
AesKeyCrypted=reader.ReadByteArray();
|
||||||
|
|
||||||
|
AesIVCrypted=reader.ReadByteArray();
|
||||||
|
|
||||||
|
|
||||||
|
PassHashEncrypted=reader.ReadByteArray();
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -202,5 +232,52 @@ namespace RageCoop.Core
|
|||||||
BlipColor=(GTA.BlipColor)reader.ReadByte();
|
BlipColor=(GTA.BlipColor)reader.ReadByte();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class PublicKeyResponse : Packet
|
||||||
|
{
|
||||||
|
public byte[] Modulus;
|
||||||
|
public byte[] Exponent;
|
||||||
|
|
||||||
|
public override void Pack(NetOutgoingMessage message)
|
||||||
|
{
|
||||||
|
#region PacketToNetOutGoingMessage
|
||||||
|
message.Write((byte)PacketTypes.PublicKeyResponse);
|
||||||
|
|
||||||
|
List<byte> byteArray = new List<byte>();
|
||||||
|
|
||||||
|
byteArray.AddArray(Modulus);
|
||||||
|
|
||||||
|
byteArray.AddArray(Exponent);
|
||||||
|
|
||||||
|
|
||||||
|
byte[] result = byteArray.ToArray();
|
||||||
|
|
||||||
|
message.Write(result.Length);
|
||||||
|
message.Write(result);
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
public override void Unpack(byte[] array)
|
||||||
|
{
|
||||||
|
#region NetIncomingMessageToPacket
|
||||||
|
var reader=new BitReader(array);
|
||||||
|
Modulus=reader.ReadByteArray();
|
||||||
|
Exponent=reader.ReadByteArray();
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class PublicKeyRequest : Packet
|
||||||
|
{
|
||||||
|
public override void Pack(NetOutgoingMessage message)
|
||||||
|
{
|
||||||
|
#region PacketToNetOutGoingMessage
|
||||||
|
message.Write((byte)PacketTypes.PublicKeyRequest);
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
public override void Unpack(byte[] array)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,8 +16,8 @@ namespace RageCoop.Core.Scripting
|
|||||||
public static readonly int OnPlayerDied = Hash("RageCoop.OnPlayerDied");
|
public static readonly int OnPlayerDied = Hash("RageCoop.OnPlayerDied");
|
||||||
public static readonly int SetAutoRespawn = Hash("RageCoop.SetAutoRespawn");
|
public static readonly int SetAutoRespawn = Hash("RageCoop.SetAutoRespawn");
|
||||||
public static readonly int NativeCall = Hash("RageCoop.NativeCall");
|
public static readonly int NativeCall = Hash("RageCoop.NativeCall");
|
||||||
// public static readonly int NativeCallNoResponse = Hash("RageCoop.NativeCallNoResponse");
|
|
||||||
public static readonly int NativeResponse = Hash("RageCoop.NativeResponse");
|
public static readonly int NativeResponse = Hash("RageCoop.NativeResponse");
|
||||||
|
public static readonly int CleanUpWorld = Hash("RageCoop.CleanUpWorld");
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get a Int32 hash of a string.
|
/// Get a Int32 hash of a string.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -10,6 +10,7 @@ namespace RageCoop.Server
|
|||||||
{
|
{
|
||||||
public class ServerPed
|
public class ServerPed
|
||||||
{
|
{
|
||||||
|
public int ID { get;internal set; }
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The ID of the ped's last vehicle.
|
/// The ID of the ped's last vehicle.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -56,6 +57,7 @@ namespace RageCoop.Server
|
|||||||
public PlayerConfig Config { get { return _config; }set { _config=value;Server.SendPlayerInfos(); } }
|
public PlayerConfig Config { get { return _config; }set { _config=value;Server.SendPlayerInfos(); } }
|
||||||
|
|
||||||
internal readonly Dictionary<int, Action<object>> Callbacks = new();
|
internal readonly Dictionary<int, Action<object>> Callbacks = new();
|
||||||
|
internal byte[] PublicKey { get; set; }
|
||||||
public bool IsReady { get; internal set; }=false;
|
public bool IsReady { get; internal set; }=false;
|
||||||
public string Username { get;internal set; } = "N/A";
|
public string Username { get;internal set; } = "N/A";
|
||||||
#region CUSTOMDATA FUNCTIONS
|
#region CUSTOMDATA FUNCTIONS
|
||||||
@ -119,115 +121,15 @@ namespace RageCoop.Server
|
|||||||
Server.Logger?.Error($">> {e.Message} <<>> {e.Source ?? string.Empty} <<>> {e.StackTrace ?? string.Empty} <<");
|
Server.Logger?.Error($">> {e.Message} <<>> {e.Source ?? string.Empty} <<>> {e.StackTrace ?? string.Empty} <<");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Send a native call to client and ignore its return value.
|
/// Send a CleanUpWorld message to this client.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="hash">The function's hash</param>
|
/// <param name="clients"></param>
|
||||||
/// <param name="args">Arguments</param>
|
public void SendCleanUpWorld(List<Client> clients = null)
|
||||||
public void SendNativeCall(ulong hash, params object[] args)
|
|
||||||
{
|
{
|
||||||
try
|
SendCustomEvent(CustomEvents.CleanUpWorld, null);
|
||||||
{
|
|
||||||
NetConnection userConnection = Server.MainNetServer.Connections.Find(x => x.RemoteUniqueIdentifier == NetID);
|
|
||||||
if (userConnection == null)
|
|
||||||
{
|
|
||||||
Server.Logger?.Error($"[Client->SendNativeCall(ulong hash, params object[] args)]: Connection \"{NetID}\" not found!");
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (args != null && args.Length == 0)
|
|
||||||
{
|
|
||||||
Server.Logger?.Error($"[Client->SendNativeCall(ulong hash, Dictionary<string, object> args)]: Missing arguments!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Packets.NativeCall packet = new()
|
|
||||||
{
|
|
||||||
Hash = hash,
|
|
||||||
Args = new List<object>(args) ?? new List<object>(),
|
|
||||||
};
|
|
||||||
|
|
||||||
NetOutgoingMessage outgoingMessage = Server.MainNetServer.CreateMessage();
|
|
||||||
packet.Pack(outgoingMessage);
|
|
||||||
Server.MainNetServer.SendMessage(outgoingMessage, userConnection, NetDeliveryMethod.ReliableOrdered, (byte)ConnectionChannel.Native);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
Server.Logger?.Error($">> {e.Message} <<>> {e.Source ?? string.Empty} <<>> {e.StackTrace ?? string.Empty} <<");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/// <summary>
|
|
||||||
/// Send a native call to client and do a callback when the response is received.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="callback">The callback to be invoked when the response is received.</param>
|
|
||||||
/// <param name="hash">The function's hash</param>
|
|
||||||
/// <param name="returnType">The return type of the response</param>
|
|
||||||
/// <param name="args">Arguments</param>
|
|
||||||
public void SendNativeCallWithResponse(Action<object> callback, GTA.Native.Hash hash, Type returnType, params object[] args)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
NetConnection userConnection = Server.MainNetServer.Connections.Find(x => x.RemoteUniqueIdentifier == NetID);
|
|
||||||
if (userConnection == null)
|
|
||||||
{
|
|
||||||
Server.Logger?.Error($"[Client->SendNativeResponse(Action<object> callback, ulong hash, Type type, params object[] args)]: Connection \"{NetID}\" not found!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (args != null && args.Length == 0)
|
|
||||||
{
|
|
||||||
Server.Logger?.Error($"[Client->SendNativeCall(ulong hash, Dictionary<string, object> args)]: Missing arguments!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
long id = ++_callbacksCount;
|
|
||||||
Callbacks.Add(id, callback);
|
|
||||||
|
|
||||||
byte returnTypeValue = 0x00;
|
|
||||||
if (returnType == typeof(int))
|
|
||||||
{
|
|
||||||
// NOTHING BECAUSE VALUE IS 0x00
|
|
||||||
}
|
|
||||||
else if (returnType == typeof(bool))
|
|
||||||
{
|
|
||||||
returnTypeValue = 0x01;
|
|
||||||
}
|
|
||||||
else if (returnType == typeof(float))
|
|
||||||
{
|
|
||||||
returnTypeValue = 0x02;
|
|
||||||
}
|
|
||||||
else if (returnType == typeof(string))
|
|
||||||
{
|
|
||||||
returnTypeValue = 0x03;
|
|
||||||
}
|
|
||||||
else if (returnType == typeof(Vector3))
|
|
||||||
{
|
|
||||||
returnTypeValue = 0x04;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Server.Logger?.Error($"[Client->SendNativeCall(ulong hash, Dictionary<string, object> args)]: Missing return type!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
NetOutgoingMessage outgoingMessage = Server.MainNetServer.CreateMessage();
|
|
||||||
new Packets.NativeResponse()
|
|
||||||
{
|
|
||||||
Hash = (ulong)hash,
|
|
||||||
Args = new List<object>(args) ?? new List<object>(),
|
|
||||||
ResultType = returnTypeValue,
|
|
||||||
ID = id
|
|
||||||
}.Pack(outgoingMessage);
|
|
||||||
Server.MainNetServer.SendMessage(outgoingMessage, userConnection, NetDeliveryMethod.ReliableOrdered, (byte)ConnectionChannel.Native);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
Server.Logger?.Error($">> {e.Message} <<>> {e.Source ?? string.Empty} <<>> {e.StackTrace ?? string.Empty} <<");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Send a native call to client and do a callback when the response received.
|
/// Send a native call to client and do a callback when the response received.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -273,18 +175,6 @@ namespace RageCoop.Server
|
|||||||
}
|
}
|
||||||
return ID;
|
return ID;
|
||||||
}
|
}
|
||||||
public void SendCleanUpWorld()
|
|
||||||
{
|
|
||||||
NetConnection userConnection = Server.MainNetServer.Connections.Find(x => x.RemoteUniqueIdentifier == NetID);
|
|
||||||
if (userConnection == null)
|
|
||||||
{
|
|
||||||
Server.Logger?.Error($"[Client->SendCleanUpWorld()]: Connection \"{NetID}\" not found!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
NetOutgoingMessage outgoingMessage = Server.MainNetServer.CreateMessage();
|
|
||||||
outgoingMessage.Write((byte)PacketTypes.CleanUpWorld);
|
|
||||||
Server.MainNetServer.SendMessage(outgoingMessage, userConnection, NetDeliveryMethod.ReliableOrdered, (byte)ConnectionChannel.Default);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SendCustomEvent(int id,List<object> args)
|
public void SendCustomEvent(int id,List<object> args)
|
||||||
{
|
{
|
||||||
|
@ -196,20 +196,7 @@ namespace RageCoop.Server.Scripting
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public void SendCleanUpWorldToAll(List<Client> clients = null)
|
public void SendCleanUpWorldToAll(List<Client> clients = null)
|
||||||
{
|
{
|
||||||
if (Server.MainNetServer.ConnectionsCount == 0)
|
SendCustomEvent(CustomEvents.CleanUpWorld,null,clients);
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
NetOutgoingMessage outgoingMessage = Server.MainNetServer.CreateMessage();
|
|
||||||
outgoingMessage.Write((byte)PacketTypes.CleanUpWorld);
|
|
||||||
if (clients == null)
|
|
||||||
{
|
|
||||||
Server.MainNetServer.SendToAll(outgoingMessage, NetDeliveryMethod.ReliableOrdered, (byte)ConnectionChannel.Default);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
clients.ForEach(client => { Server.MainNetServer.SendMessage(outgoingMessage,client.Connection, NetDeliveryMethod.ReliableOrdered, (byte)ConnectionChannel.Default); });
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -248,7 +235,7 @@ namespace RageCoop.Server.Scripting
|
|||||||
/// <param name="eventHash">An unique identifier of the event</param>
|
/// <param name="eventHash">An unique identifier of the event</param>
|
||||||
/// <param name="args">The objects conataing your data, supported types: byte, short, ushort, int, uint, long, ulong, float, bool, string.</param>
|
/// <param name="args">The objects conataing your data, supported types: byte, short, ushort, int, uint, long, ulong, float, bool, string.</param>
|
||||||
/// <param name="targets">The target clients to send. Leave it null to send to all clients</param>
|
/// <param name="targets">The target clients to send. Leave it null to send to all clients</param>
|
||||||
public void SendCustomEvent(int eventHash,List<object> args,List<Client> targets=null)
|
public void SendCustomEvent(int eventHash,List<object> args=null,List<Client> targets=null)
|
||||||
{
|
{
|
||||||
targets ??= new(Server.Clients.Values);
|
targets ??= new(Server.Clients.Values);
|
||||||
var p = new Packets.CustomEvent()
|
var p = new Packets.CustomEvent()
|
||||||
|
@ -32,6 +32,11 @@ namespace RageCoop.Server.Scripting
|
|||||||
{
|
{
|
||||||
public int ID { get; set; }
|
public int ID { get; set; }
|
||||||
public string Username { get; set; }
|
public string Username { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The hashed value of client password, sent with RSA asymmetric encryption.
|
||||||
|
/// </summary>
|
||||||
|
public string PasswordHash { get; set; }
|
||||||
public IPEndPoint EndPoint { get; set; }
|
public IPEndPoint EndPoint { get; set; }
|
||||||
public void Deny(string reason)
|
public void Deny(string reason)
|
||||||
{
|
{
|
||||||
|
78
RageCoop.Server/Security.cs
Normal file
78
RageCoop.Server/Security.cs
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Net;
|
||||||
|
using System.IO;
|
||||||
|
using RageCoop.Core;
|
||||||
|
using System.Runtime.Serialization;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
namespace RageCoop.Server
|
||||||
|
{
|
||||||
|
internal class Security
|
||||||
|
{
|
||||||
|
private readonly Logger Logger;
|
||||||
|
public Security(Logger logger)
|
||||||
|
{
|
||||||
|
Logger= logger;
|
||||||
|
}
|
||||||
|
public RSA RSA=RSA.Create(2048);
|
||||||
|
private Dictionary<IPEndPoint, Aes> SecuredConnections = new Dictionary<IPEndPoint, Aes>();
|
||||||
|
|
||||||
|
public bool HasSecuredConnection(IPEndPoint target)
|
||||||
|
{
|
||||||
|
return SecuredConnections.ContainsKey(target);
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] Encrypt(byte[] data, IPEndPoint target)
|
||||||
|
{
|
||||||
|
var ms=new MemoryStream();
|
||||||
|
using (var cs = new CryptoStream(ms, SecuredConnections[target].CreateEncryptor(), CryptoStreamMode.Write))
|
||||||
|
{
|
||||||
|
cs.Write(data, 0, data.Length);
|
||||||
|
}
|
||||||
|
return ms.ToArray();
|
||||||
|
}
|
||||||
|
public byte[] Decrypt(byte[] data, IPEndPoint target)
|
||||||
|
{
|
||||||
|
return new CryptoStream(new MemoryStream(data), SecuredConnections[target].CreateDecryptor(), CryptoStreamMode.Read).ReadToEnd();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddConnection(IPEndPoint endpoint, byte[] cryptedKey,byte[] cryptedIV)
|
||||||
|
{
|
||||||
|
var key = RSA.Decrypt(cryptedKey, RSAEncryptionPadding.Pkcs1);
|
||||||
|
var iv = RSA.Decrypt(cryptedIV, RSAEncryptionPadding.Pkcs1);
|
||||||
|
// Logger?.Debug($"key:{key.Dump()}, iv:{iv.Dump()}");
|
||||||
|
var conAes = Aes.Create();
|
||||||
|
conAes.Key = key;
|
||||||
|
conAes.IV = iv;
|
||||||
|
if (!SecuredConnections.ContainsKey(endpoint))
|
||||||
|
{
|
||||||
|
SecuredConnections.Add(endpoint,conAes);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SecuredConnections[endpoint] = conAes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public void RemoveConnection(IPEndPoint ep)
|
||||||
|
{
|
||||||
|
if (SecuredConnections.ContainsKey(ep))
|
||||||
|
{
|
||||||
|
SecuredConnections.Remove(ep);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public void GetPublicKey(out byte[] modulus, out byte[] exponent)
|
||||||
|
{
|
||||||
|
var key = RSA.ExportParameters(false);
|
||||||
|
modulus = key.Modulus;
|
||||||
|
exponent = key.Exponent;
|
||||||
|
}
|
||||||
|
public void ClearConnections()
|
||||||
|
{
|
||||||
|
SecuredConnections.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -39,11 +39,13 @@ namespace RageCoop.Server
|
|||||||
private Resources Resources;
|
private Resources Resources;
|
||||||
public API API;
|
public API API;
|
||||||
public Logger Logger;
|
public Logger Logger;
|
||||||
|
private Security Security;
|
||||||
public Server(Logger logger=null)
|
public Server(Logger logger=null)
|
||||||
{
|
{
|
||||||
Logger=logger;
|
Logger=logger;
|
||||||
API=new API(this);
|
API=new API(this);
|
||||||
Resources=new Resources(this);
|
Resources=new Resources(this);
|
||||||
|
Security=new Security(Logger);
|
||||||
Logger?.Info("================");
|
Logger?.Info("================");
|
||||||
Logger?.Info($"Server bound to: 0.0.0.0:{MainSettings.Port}");
|
Logger?.Info($"Server bound to: 0.0.0.0:{MainSettings.Port}");
|
||||||
Logger?.Info($"Server version: {Assembly.GetCallingAssembly().GetName().Version}");
|
Logger?.Info($"Server version: {Assembly.GetCallingAssembly().GetName().Version}");
|
||||||
@ -57,10 +59,12 @@ namespace RageCoop.Server
|
|||||||
MaximumConnections = MainSettings.MaxPlayers,
|
MaximumConnections = MainSettings.MaxPlayers,
|
||||||
EnableUPnP = false,
|
EnableUPnP = false,
|
||||||
AutoFlushSendQueue = true,
|
AutoFlushSendQueue = true,
|
||||||
|
MaximumTransmissionUnit=2000, // PublicKeyResponse
|
||||||
};
|
};
|
||||||
|
|
||||||
config.EnableMessageType(NetIncomingMessageType.ConnectionApproval);
|
config.EnableMessageType(NetIncomingMessageType.ConnectionApproval);
|
||||||
config.EnableMessageType(NetIncomingMessageType.ConnectionLatencyUpdated);
|
config.EnableMessageType(NetIncomingMessageType.ConnectionLatencyUpdated);
|
||||||
|
config.EnableMessageType(NetIncomingMessageType.UnconnectedData);
|
||||||
|
|
||||||
MainNetServer = new NetServer(config);
|
MainNetServer = new NetServer(config);
|
||||||
MainNetServer.Start();
|
MainNetServer.Start();
|
||||||
@ -170,8 +174,6 @@ namespace RageCoop.Server
|
|||||||
{
|
{
|
||||||
Logger?.Info("Listening for clients");
|
Logger?.Info("Listening for clients");
|
||||||
Logger?.Info("Please use CTRL + C if you want to stop the server!");
|
Logger?.Info("Please use CTRL + C if you want to stop the server!");
|
||||||
|
|
||||||
|
|
||||||
while (!Program.ReadyToStop)
|
while (!Program.ReadyToStop)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@ -191,10 +193,10 @@ namespace RageCoop.Server
|
|||||||
Resources.StopAll();
|
Resources.StopAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
Client sender;
|
|
||||||
private void ProcessMessage(NetIncomingMessage message)
|
private void ProcessMessage(NetIncomingMessage message)
|
||||||
{
|
{
|
||||||
if(message == null) { return; }
|
Client sender;
|
||||||
|
if (message == null) { return; }
|
||||||
switch (message.MessageType)
|
switch (message.MessageType)
|
||||||
{
|
{
|
||||||
case NetIncomingMessageType.ConnectionApproval:
|
case NetIncomingMessageType.ConnectionApproval:
|
||||||
@ -214,12 +216,12 @@ namespace RageCoop.Server
|
|||||||
|
|
||||||
Packets.Handshake packet = new();
|
Packets.Handshake packet = new();
|
||||||
packet.Unpack(data);
|
packet.Unpack(data);
|
||||||
|
|
||||||
GetHandshake(message.SenderConnection, packet);
|
GetHandshake(message.SenderConnection, packet);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
Logger?.Info($"IP [{message.SenderConnection.RemoteEndPoint.Address}] was blocked, reason: {e.Message}");
|
Logger?.Info($"IP [{message.SenderConnection.RemoteEndPoint.Address}] was blocked, reason: {e.Message}");
|
||||||
|
Logger?.Error(e);
|
||||||
message.SenderConnection.Deny(e.Message);
|
message.SenderConnection.Deny(e.Message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -413,6 +415,19 @@ namespace RageCoop.Server
|
|||||||
case NetIncomingMessageType.VerboseDebugMessage:
|
case NetIncomingMessageType.VerboseDebugMessage:
|
||||||
Logger?.Debug(message.ReadString());
|
Logger?.Debug(message.ReadString());
|
||||||
break;
|
break;
|
||||||
|
case NetIncomingMessageType.UnconnectedData:
|
||||||
|
{
|
||||||
|
if (message.ReadByte()==(byte)PacketTypes.PublicKeyRequest)
|
||||||
|
{
|
||||||
|
var msg = MainNetServer.CreateMessage();
|
||||||
|
var p=new Packets.PublicKeyResponse();
|
||||||
|
Security.GetPublicKey(out p.Modulus,out p.Exponent);
|
||||||
|
p.Pack(msg);
|
||||||
|
Logger?.Debug($"Sending public key to {message.SenderEndPoint}, length:{msg.LengthBytes}");
|
||||||
|
MainNetServer.SendUnconnectedMessage(msg, message.SenderEndPoint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
Logger?.Error(string.Format("Unhandled type: {0} {1} bytes {2} | {3}", message.MessageType, message.LengthBytes, message.DeliveryMethod, message.SequenceChannel));
|
Logger?.Error(string.Format("Unhandled type: {0} {1} bytes {2} | {3}", message.MessageType, message.LengthBytes, message.DeliveryMethod, message.SequenceChannel));
|
||||||
break;
|
break;
|
||||||
@ -480,12 +495,25 @@ namespace RageCoop.Server
|
|||||||
connection.Deny("Username is already taken!");
|
connection.Deny("Username is already taken!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
string passhash;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Security.AddConnection(connection.RemoteEndPoint, packet.AesKeyCrypted,packet.AesIVCrypted);
|
||||||
|
passhash=Security.Decrypt(packet.PassHashEncrypted,connection.RemoteEndPoint).GetString();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logger?.Error($"Cannot process handshake packet from {connection.RemoteEndPoint}");
|
||||||
|
Logger?.Error(ex);
|
||||||
|
connection.Deny("Malformed handshak packet!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
var args = new HandshakeEventArgs()
|
var args = new HandshakeEventArgs()
|
||||||
{
|
{
|
||||||
EndPoint=connection.RemoteEndPoint,
|
EndPoint=connection.RemoteEndPoint,
|
||||||
ID=packet.PedID,
|
ID=packet.PedID,
|
||||||
Username=packet.Username
|
Username=packet.Username,
|
||||||
|
PasswordHash=passhash,
|
||||||
};
|
};
|
||||||
API.Events.InvokePlayerHandshake(args);
|
API.Events.InvokePlayerHandshake(args);
|
||||||
if (args.Cancel)
|
if (args.Cancel)
|
||||||
@ -495,6 +523,7 @@ namespace RageCoop.Server
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
connection.Approve();
|
||||||
|
|
||||||
Client tmpClient;
|
Client tmpClient;
|
||||||
|
|
||||||
@ -510,23 +539,14 @@ namespace RageCoop.Server
|
|||||||
ID=packet.PedID,
|
ID=packet.PedID,
|
||||||
Player = new()
|
Player = new()
|
||||||
{
|
{
|
||||||
|
ID= packet.PedID,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);;
|
);;
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger?.Debug($"Handshake sucess, Player:{packet.Username} PedID:{packet.PedID}");
|
Logger?.Debug($"Handshake sucess, Player:{packet.Username} PedID:{packet.PedID}");
|
||||||
NetOutgoingMessage outgoingMessage = MainNetServer.CreateMessage();
|
|
||||||
|
|
||||||
// Create a new handshake packet
|
|
||||||
new Packets.Handshake()
|
|
||||||
{
|
|
||||||
PedID = packet.PedID,
|
|
||||||
Username = string.Empty,
|
|
||||||
ModVersion = string.Empty,
|
|
||||||
}.Pack(outgoingMessage);
|
|
||||||
// Accept the connection and send back a new handshake packet with the connection ID
|
|
||||||
connection.Approve(outgoingMessage);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// The connection has been approved, now we need to send all other players to the new player and the new player to all players
|
// The connection has been approved, now we need to send all other players to the new player and the new player to all players
|
||||||
|
Reference in New Issue
Block a user