WriteHeader() public method

Writes the packet header.
public WriteHeader ( ) : void
return void
        /// <summary>
        /// Send information about this CityServer to the LoginServer...
        /// </summary>
        /// <param name="Client">The client connected to the LoginServer.</param>
        public static void SendServerInfo(NetworkClient Client)
        {
            PacketStream Packet = new PacketStream(0x64, 0);
            Packet.WriteHeader();

            MemoryStream PacketBody = new MemoryStream();
            BinaryWriter PacketWriter = new BinaryWriter(PacketBody);

            PacketWriter.Write((string)GlobalSettings.Default.CityName);
            PacketWriter.Write((string)GlobalSettings.Default.CityDescription);
            PacketWriter.Write((string)Settings.BINDING.Address.ToString());
            PacketWriter.Write((int)Settings.BINDING.Port);
            PacketWriter.Write((byte)1); //CityInfoStatus.OK
            PacketWriter.Write((ulong)GlobalSettings.Default.CityThumbnail);
            PacketWriter.Write((string)GlobalSettings.Default.ServerID);
            PacketWriter.Write((ulong)GlobalSettings.Default.Map);
            PacketWriter.Flush();

            Packet.WriteUInt16((ushort)(PacketBody.ToArray().Length + PacketHeaders.UNENCRYPTED));

            Packet.Write(PacketBody.ToArray(), 0, (int)PacketBody.ToArray().Length);
            Packet.Flush();

            PacketWriter.Close();

            Client.Send(Packet.ToArray());
        }
示例#2
0
        public static void HandleChallengeResponse(NetworkClient Client, ProcessedPacket P)
        {
            PacketStream OutPacket;

            if (P.DecryptedSuccessfully)
            {
                int Length = P.ReadByte();
                byte[] CResponse;

                if (P.BufferLength >= Length)
                    CResponse = P.ReadBytes(Length);
                else
                {
                    //Authentication failed, so send this packet unencrypted.
                    OutPacket = new PacketStream((byte)PacketType.LOGIN_FAILURE_CITY, 0);
                    OutPacket.WriteHeader();
                    OutPacket.WriteUInt16((ushort)(PacketHeaders.UNENCRYPTED + 1));
                    OutPacket.WriteByte(0x03); //Bad challenge response.
                    Client.Send(OutPacket.ToArray());

                    Logger.LogInfo("Sent LOGIN_FAILURE_CITY!");
                    return;
                }

                AESDecryptionArgs DecryptionArgs = Client.ClientEncryptor.GetDecryptionArgsContainer().AESDecryptArgs;

                if (DecryptionArgs.Challenge.SequenceEqual(CResponse))
                {
                    OutPacket = new PacketStream((byte)PacketType.LOGIN_SUCCESS_CITY, 0);
                    OutPacket.WriteByte(0x01);
                    Client.SendEncrypted((byte)PacketType.LOGIN_SUCCESS_CITY, OutPacket.ToArray());

                    Logger.LogInfo("Sent LOGIN_SUCCESS_CITY!");
                }
                else
                {
                    //Authentication failed, so send this packet unencrypted.
                    OutPacket = new PacketStream((byte)PacketType.LOGIN_FAILURE_CITY, 0);
                    OutPacket.WriteHeader();
                    OutPacket.WriteUInt16((ushort)(PacketHeaders.UNENCRYPTED + 1));
                    OutPacket.WriteByte(0x03); //Bad challenge response.
                    Client.Send(OutPacket.ToArray());

                    Logger.LogInfo("Sent LOGIN_FAILURE_CITY!");
                }
            }
            else
            {
                //Authentication failed, so send this packet unencrypted.
                OutPacket = new PacketStream((byte)PacketType.LOGIN_FAILURE_CITY, 0);
                OutPacket.WriteHeader();
                OutPacket.WriteUInt16((ushort)(PacketHeaders.UNENCRYPTED + 1));
                OutPacket.WriteByte(0x03); //Bad challenge response.
                Client.Send(OutPacket.ToArray());

                Debug.WriteLine("HandleChallengeResponse - decryption failed!");
                Logger.LogInfo("Sent LOGIN_FAILURE_CITY!");
            }
        }
        /// <summary>
        /// A client requested login.
        /// </summary>
        /// <param name="Client">NetworkClient instance.</param>
        /// <param name="Packet">ProcessedPacket instance.</param>
        public static void InitialClientConnect(NetworkClient Client, ProcessedPacket Packet)
        {
            Console.WriteLine("Server receives data - test 1");

            PacketStream EncryptedPacket = new PacketStream(0x02, 0);
            EncryptedPacket.WriteHeader();

            ClientPublicKey = Packet.ReadBytes((Packet.ReadByte()));

            AESEncryptor Enc = (AESEncryptor)Client.ClientEncryptor;
            Enc.NOnce = Packet.ReadBytes((Packet.ReadByte()));
            Enc.PublicKey = ClientPublicKey;
            Enc.PrivateKey = ServerPrivateKey;
            Client.ClientEncryptor = Enc;

            //THIS IS IMPORTANT - public key must be derived from private!
            ServerPublicKey = ServerPrivateKey.PublicKey.ToByteArray();

            ChallengeResponse = new byte[16];
            m_Random.GetNonZeroBytes(ChallengeResponse);

            MemoryStream StreamToEncrypt = new MemoryStream();
            BinaryWriter Writer = new BinaryWriter(StreamToEncrypt);
            Writer.Write(ChallengeResponse, 0, ChallengeResponse.Length);
            Writer.Flush();

            byte[] EncryptedData = StaticStaticDiffieHellman.Encrypt(ServerPrivateKey,
                ECDiffieHellmanCngPublicKey.FromByteArray(ClientPublicKey, CngKeyBlobFormat.EccPublicBlob), Enc.NOnce, 
                StreamToEncrypt.ToArray());

            EncryptedPacket.WriteUInt16((ushort)(PacketHeaders.UNENCRYPTED + 
                (1 + ServerPublicKey.Length) + 
                (1 + EncryptedData.Length)));

            EncryptedPacket.WriteByte((byte)ServerPublicKey.Length);
            EncryptedPacket.WriteBytes(ServerPublicKey);
            EncryptedPacket.WriteByte((byte)EncryptedData.Length);
            EncryptedPacket.WriteBytes(EncryptedData);

            Client.Send(EncryptedPacket.ToArray());

            NetworkFacade.Listener.UpdateClient(Client);

            Console.WriteLine("Test 1: passed!");
        }
        //First packet sent from client to server.
        public static void SendInitialConnectPacket(NetworkClient Client, string Username)
        {
            PacketStream InitialPacket = new PacketStream(0x01, 0);
            InitialPacket.WriteHeader();

            ECDiffieHellmanCng PrivateKey = Client.ClientEncryptor.GetDecryptionArgsContainer().AESDecryptArgs.PrivateKey;
            //IMPORTANT: Public key must derive from the private key!
            PacketHandlers.ClientPublicKey = PrivateKey.PublicKey.ToByteArray();

            byte[] NOnce = Client.ClientEncryptor.GetDecryptionArgsContainer().AESDecryptArgs.NOnce;

            InitialPacket.WriteUInt16((ushort)((byte)PacketHeaders.UNENCRYPTED +
                (PacketHandlers.ClientPublicKey.Length + 1) + (NOnce.Length + 1)));

            InitialPacket.WriteByte((byte)PacketHandlers.ClientPublicKey.Length);
            InitialPacket.WriteBytes(PacketHandlers.ClientPublicKey);

            InitialPacket.WriteByte((byte)NOnce.Length);
            InitialPacket.WriteBytes(NOnce);

            Client.Send(InitialPacket.ToArray());
        }
        /**
        * Actual packet handlers
        */
        public static void HandleLoginRequest(NetworkClient Client, ProcessedPacket P)
        {
            Logger.LogInfo("Received LoginRequest!\r\n");

            byte AccountStrLength = (byte)P.ReadByte();
            byte[] AccountNameBuf = new byte[AccountStrLength];
            P.Read(AccountNameBuf, 0, AccountStrLength);
            string AccountName = SanitizeAccount(Encoding.ASCII.GetString(AccountNameBuf));
            Logger.LogInfo("Accountname: " + AccountName + "\r\n");

            byte HashLength = (byte)P.ReadByte();
            byte[] HashBuf = new byte[HashLength];
            P.Read(HashBuf, 0, HashLength);

            if (AccountName == "")
            {
                PacketStream OutPacket = new PacketStream((byte)PacketType.LOGIN_FAILURE, 2);
                OutPacket.WriteHeader();
                OutPacket.WriteByte(0x01);
                Client.Send(OutPacket.ToArray());

                Logger.LogInfo("Bad accountname - sent SLoginFailResponse!\r\n");
                Client.Disconnect();
                return;
            }

            using (var db = DataAccess.Get())
            {
                var account = db.Accounts.GetByUsername(AccountName);
                byte KeyLength = (byte)P.ReadByte();
                byte[] EncKey = new byte[KeyLength];
                P.Read(EncKey, 0, KeyLength);

                //TODO: Do something with this...
                byte Version1 = (byte)P.ReadByte();
                byte Version2 = (byte)P.ReadByte();
                byte Version3 = (byte)P.ReadByte();
                byte Version4 = (byte)P.ReadByte();

                string ClientVersion = Version1.ToString() + "." + Version2.ToString() + "." + Version3.ToString() +
                    "." + Version4.ToString();

                if (ClientVersion != GlobalSettings.Default.ClientVersion)
                {
                    PacketStream OutPacket = new PacketStream((byte)PacketType.INVALID_VERSION, 2);
                    OutPacket.WriteHeader();
                    OutPacket.WriteByte(0x01);
                    Client.Send(OutPacket.ToArray());

                    Logger.LogInfo("Bad version - sent SInvalidVersion!\r\n");
                    Client.Disconnect();
                    return;
                }

                if (!GlobalSettings.Default.CreateAccountsOnLogin)
                {
                    Logger.LogInfo("Done reading LoginRequest, checking account...\r\n");

                    if (account == null)
                    {
                        PacketStream OutPacket = new PacketStream((byte)PacketType.LOGIN_FAILURE, 2);
                        OutPacket.WriteHeader();
                        OutPacket.WriteByte(0x01);
                        Client.Send(OutPacket.ToArray());

                        Logger.LogInfo("Bad accountname - sent SLoginFailResponse!\r\n");
                        Client.Disconnect();
                        return;
                    }
                    else
                        Client.ClientEncryptor = new ARC4Encryptor(account.Password, EncKey);
                }
                else
                {
                    if (account == null)
                    {
                        try
                        {
                            db.Accounts.Create(new Account
                            {
                                AccountName = AccountName.ToLower(),
                                Password = Convert.ToBase64String(HashBuf)
                            });
                        }
                        catch (Exception)
                        {
                            PacketStream OutPacket = new PacketStream((byte)PacketType.LOGIN_FAILURE, 2);
                            OutPacket.WriteHeader();
                            OutPacket.WriteByte(0x01);
                            Client.Send(OutPacket.ToArray());

                            Logger.LogInfo("Bad accountname - sent SLoginFailResponse!\r\n");
                            Client.Disconnect();
                            return;
                        }

                        account = db.Accounts.GetByUsername(AccountName);
                    }

                    Client.ClientEncryptor = new ARC4Encryptor(account.Password, EncKey);
                }

                if (account.IsCorrectPassword(AccountName, HashBuf))
                {
                    //0x01 = InitLoginNotify
                    PacketStream OutPacket = new PacketStream((byte)PacketType.LOGIN_NOTIFY, 1);
                    OutPacket.WriteHeader();
                    OutPacket.WriteByte(0x01);
                    Client.ClientEncryptor.Username = AccountName;
                    Client.Send(OutPacket.ToArray());

                    Logger.LogInfo("Sent InitLoginNotify!\r\n");
                }
                else
                {
                    PacketStream OutPacket = new PacketStream((byte)PacketType.LOGIN_FAILURE, 2);
                    OutPacket.WriteHeader();
                    OutPacket.WriteByte(0x02);
                    Client.Send(OutPacket.ToArray());

                    Logger.LogInfo("Bad password - sent SLoginFailResponse!\r\n");
                    Client.Disconnect();
                    return;
                }
            }

            //Client was modified, update it.
            NetworkFacade.ClientListener.UpdateClient(Client);
        }
示例#6
0
        //uh, this is a little silly.
        private void SendOneOff(NetworkClient client, VMNetTick tick)
        {
            var ticks = new VMNetTickList { Ticks = new List<VMNetTick>() { tick }, ImmediateMode = true };
            byte[] data;
            using (var stream = new MemoryStream())
            {
                using (var writer = new BinaryWriter(stream))
                {
                    ticks.SerializeInto(writer);
                }

                data = stream.ToArray();
            }

            using (var stream = new PacketStream((byte)PacketType.VM_PACKET, 0))
            {
                stream.WriteHeader();
                stream.WriteInt32(data.Length + (int)PacketHeaders.UNENCRYPTED);
                stream.WriteBytes(data);
                client.Send(stream.ToArray());
            }
        }
示例#7
0
        /// <summary>
        /// Client wanted to log in!
        /// </summary>
        public static void HandleLoginRequest(NetworkClient Client, ProcessedPacket P)
        {
            try
            {
                Logger.LogInfo("Received LoginRequest!\r\n");

                byte Version1 = (byte)P.ReadByte();
                byte Version2 = (byte)P.ReadByte();
                byte Version3 = (byte)P.ReadByte();
                byte Version4 = (byte)P.ReadByte();

                string ClientVersion = Version1.ToString() + "." + Version2.ToString() + "." + Version3.ToString() +
                    "." + Version4.ToString();

                if (ClientVersion != GlobalSettings.Default.ClientVersion)
                {
                    PacketStream OutPacket = new PacketStream((byte)PacketType.INVALID_VERSION, 2);
                    OutPacket.WriteHeader();
                    OutPacket.WriteByte(0x01);
                    Client.Send(OutPacket.ToArray());

                    Logger.LogInfo("Bad version - sent SInvalidVersion!\r\n");
                    Client.Disconnect();
                    return;
                }

                PacketStream EncryptedPacket = new PacketStream((byte)PacketType.LOGIN_NOTIFY, 0);
                EncryptedPacket.WriteHeader();

                AESEncryptor Enc = (AESEncryptor)Client.ClientEncryptor;

                if (Enc == null)
                    Enc = new AESEncryptor("");

                Enc.PublicKey = P.ReadBytes((P.ReadByte()));
                Enc.NOnce = P.ReadBytes((P.ReadByte()));
                Enc.PrivateKey = NetworkFacade.ServerKey;
                Client.ClientEncryptor = Enc;

                MemoryStream StreamToEncrypt = new MemoryStream();
                BinaryWriter Writer = new BinaryWriter(StreamToEncrypt);
                Writer.Write(Enc.Challenge, 0, Enc.Challenge.Length);
                Writer.Flush();

                byte[] EncryptedData = StaticStaticDiffieHellman.Encrypt(NetworkFacade.ServerKey,
                    System.Security.Cryptography.ECDiffieHellmanCngPublicKey.FromByteArray(Enc.PublicKey,
                    System.Security.Cryptography.CngKeyBlobFormat.EccPublicBlob), Enc.NOnce, StreamToEncrypt.ToArray());

                EncryptedPacket.WriteUInt16((ushort)(PacketHeaders.UNENCRYPTED +
                    (1 + NetworkFacade.ServerPublicKey.Length) +
                    (1 + EncryptedData.Length)));

                EncryptedPacket.WriteByte((byte)NetworkFacade.ServerPublicKey.Length);
                EncryptedPacket.WriteBytes(NetworkFacade.ServerPublicKey);
                EncryptedPacket.WriteByte((byte)EncryptedData.Length);
                EncryptedPacket.WriteBytes(EncryptedData);

                Client.Send(EncryptedPacket.ToArray());
            }
            //This should HOPEFULLY wade off clients sending unreadable (I.E old protocol) packets...
            catch (Exception E)
            {
                Logger.LogDebug("Error while handling login request, disconnecting client: " +
                    E.ToString());
                Client.Disconnect();
                return;
            }
        }
示例#8
0
        /// <summary>
        /// Client wanted to retire a character.
        /// </summary>
        public static void HandleCharacterRetirement(NetworkClient Client, ProcessedPacket P)
        {
            PacketStream Packet;

            string AccountName = P.ReadString();
            string GUID = P.ReadString();

            if (AccountName == string.Empty || GUID == string.Empty)
                return;

            using (var db = DataAccess.Get())
            {
                Account Acc = db.Accounts.GetByUsername(AccountName);
                IQueryable<Character> Query = db.Characters.GetForAccount(Acc.AccountID);

                //F**K, I hate LINQ.
                Guid CharGUID = new Guid(GUID);
                Character Char = Query.Where(x => x.GUID == CharGUID).SingleOrDefault();

                if (Char != null)
                    db.Characters.RetireCharacter(Char);
                else
                    return;

                //This actually updates the record, not sure how.
                Acc.NumCharacters--;

                if (Char != null)
                {
                    CityInfo CInfo = NetworkFacade.CServerListener.GetCityServer(Char.City);

                    //Just in case...
                    if (CInfo != null)
                    {
                        Packet = new PacketStream(0x02, 0);
                        Packet.WriteHeader();

                        ushort PacketLength = (ushort)(PacketHeaders.UNENCRYPTED + 4 + GUID.Length + 1);

                        Packet.WriteUInt16(PacketLength);
                        Packet.WriteInt32(Acc.AccountID);
                        Packet.WriteString(GUID);
                        CInfo.Client.Send(Packet.ToArray());
                    }
                }
            }

            Packet = new PacketStream((byte)PacketType.RETIRE_CHARACTER_STATUS, 0);
            Packet.WriteString(GUID);
            Client.SendEncrypted((byte)PacketType.RETIRE_CHARACTER_STATUS, Packet.ToArray());
        }
示例#9
0
        public static void SendLoginRequest(LoginArgsContainer Args)
        {
            PacketStream InitialPacket = new PacketStream((byte)PacketType.LOGIN_REQUEST, 0);
            InitialPacket.WriteHeader();

            //ECDiffieHellmanCng PrivateKey = Args.Client.ClientEncryptor.GetDecryptionArgsContainer()
            //    .AESDecryptArgs.PrivateKey;
            //IMPORTANT: Public key must derive from the private key!
            //byte[] ClientPublicKey = PrivateKey.PublicKey.ToByteArray();

            byte[] NOnce = Args.Client.ClientEncryptor.GetDecryptionArgsContainer().AESDecryptArgs.NOnce;

            //InitialPacket.WriteInt32(((byte)PacketHeaders.UNENCRYPTED +
            //    /*4 is for version*/ 4 + (ClientPublicKey.Length + 1) + (NOnce.Length + 1)));

            SaltedHash Hash = new SaltedHash(new SHA512Managed(), Args.Username.Length);
            byte[] HashBuf = Hash.ComputePasswordHash(Args.Username, Args.Password);
            PlayerAccount.Hash = HashBuf;

            string[] Version = GlobalSettings.Default.ClientVersion.Split('.');

            InitialPacket.WriteByte((byte)int.Parse(Version[0])); //Version 1
            InitialPacket.WriteByte((byte)int.Parse(Version[1])); //Version 2
            InitialPacket.WriteByte((byte)int.Parse(Version[2])); //Version 3
            InitialPacket.WriteByte((byte)int.Parse(Version[3])); //Version 4

            //InitialPacket.WriteByte((byte)ClientPublicKey.Length);
            //InitialPacket.WriteBytes(ClientPublicKey);

            InitialPacket.WriteByte((byte)NOnce.Length);
            InitialPacket.WriteBytes(NOnce);

            Args.Client.Send(InitialPacket.ToArray());
        }
        /// <summary>
        /// A client wanted to transfer to this server, so a token was generated by the login server.
        /// </summary>
        public static void HandleClientToken(NetworkClient Client, ProcessedPacket P)
        {
            try
            {
                ClientToken Token = new ClientToken();
				byte CharacterCreate = (byte)P.ReadByte();
                Token.AccountID = P.ReadInt32();
                Token.ClientIP = P.ReadString();
				int ClientPort = P.ReadInt32();
                Token.CharacterGUID = P.ReadString();
                Token.Token = P.ReadString();

				PacketStream PlayerOnlinePacket = new PacketStream(0x67, 0);
				PlayerOnlinePacket.WriteHeader();
				PlayerOnlinePacket.WriteUInt16((ushort)(PacketHeaders.UNENCRYPTED + 1 +
					Token.Token.Length + 1 + Token.ClientIP.Length + 1 + 4));

				if (CharacterCreate == 0)
				{
					if (NetworkFacade.CurrentSession.GetPlayer(Token.CharacterGUID) == null)
					{
						NetworkClient WaitingClient = NetworkFacade.NetworkListener.GetClient(Token.ClientIP, ClientPort);
						//Uh-oh, someone's waiting for their token!
						if(WaitingClient != null)
						{
							PacketStream SuccessPacket = new PacketStream((byte)PacketType.CITY_TOKEN, 0);
							SuccessPacket.WriteByte((byte)CityTransferStatus.Success);
							WaitingClient.SendEncrypted((byte)PacketType.CITY_TOKEN, SuccessPacket.ToArray());
						}

						PlayerOnlinePacket.WriteByte(0x01);
						PlayerOnlinePacket.WriteString(Token.Token);
						PlayerOnlinePacket.WriteString(Token.ClientIP);
						PlayerOnlinePacket.WriteInt32(ClientPort);

						lock (NetworkFacade.TransferringClients)
						{
							if (!NetworkFacade.TransferringClients.Contains(Token))
								NetworkFacade.TransferringClients.Add(Token);
						}

						Client.Send(PlayerOnlinePacket.ToArray());
					}
					else
					{
						PlayerOnlinePacket.WriteByte(0x02);
						PlayerOnlinePacket.WriteString(Token.Token);
						PlayerOnlinePacket.WriteString(Token.ClientIP);
						PlayerOnlinePacket.WriteInt32(ClientPort);

						Client.Send(PlayerOnlinePacket.ToArray());
					}
				}
				else
				{
					NetworkClient WaitingClient = NetworkFacade.NetworkListener.GetClient(Token.ClientIP, ClientPort);
					//Uh-oh, someone's waiting for their token!
					if (WaitingClient != null)
					{
						PacketStream SuccessPacket = new PacketStream((byte)PacketType.CITY_TOKEN, 0);
						SuccessPacket.WriteByte((byte)CityTransferStatus.Success);
						WaitingClient.SendEncrypted((byte)PacketType.CITY_TOKEN, SuccessPacket.ToArray());
					}

					if (!NetworkFacade.TransferringClients.Contains(Token))
						NetworkFacade.TransferringClients.Add(Token);
				}
            }
            catch (Exception E)
            {
                Logger.LogDebug("Exception in HandleClientToken: " + E.ToString());
            }
        }
        /**
        * Actual packet handlers
        */
        public static void HandleLoginRequest(NetworkClient Client, ProcessedPacket P)
        {
            Logger.LogInfo("Received LoginRequest!\r\n");

            byte AccountStrLength = (byte)P.ReadByte();
            byte[] AccountNameBuf = new byte[AccountStrLength];
            P.Read(AccountNameBuf, 0, AccountStrLength);
            string AccountName = Encoding.ASCII.GetString(AccountNameBuf);
            Logger.LogInfo("Accountname: " + AccountName + "\r\n");

            byte HashLength = (byte)P.ReadByte();
            byte[] HashBuf = new byte[HashLength];
            P.Read(HashBuf, 0, HashLength);

            using (var db = DataAccess.Get())
            {
                var account = db.Accounts.GetByUsername(AccountName);

                byte KeyLength = (byte)P.ReadByte();
                byte[] EncKey = new byte[KeyLength];
                P.Read(EncKey, 0, KeyLength);
                Client.ClientEncryptor = new ARC4Encryptor(account.Password, EncKey);

                //TODO: Do something with this...
                byte Version1 = (byte)P.ReadByte();
                byte Version2 = (byte)P.ReadByte();
                byte Version3 = (byte)P.ReadByte();
                byte Version4 = (byte)P.ReadByte();

                Logger.LogInfo("Done reading LoginRequest, checking account...\r\n");

                if (account == null)
                {
                    PacketStream OutPacket = new PacketStream(0x02, 2);
                    OutPacket.WriteHeader();
                    OutPacket.WriteByte(0x01);
                    Client.Send(OutPacket.ToArray());

                    Logger.LogInfo("Bad accountname - sent SLoginFailResponse!\r\n");
                    Client.Disconnect();
                    return;
                }

                if (account.IsCorrectPassword(AccountName, HashBuf))
                {
                    //0x01 = InitLoginNotify
                    PacketStream OutPacket = new PacketStream(0x01, 1);
                    OutPacket.WriteHeader();
                    OutPacket.WriteByte(0x01);
                    Client.ClientEncryptor.Username = AccountName;
                    //This is neccessary to encrypt packets.
                    //TODO: Put something else here
                    //Client.Password = Account.GetPassword(AccountName);
                    Client.Send(OutPacket.ToArray());

                    Logger.LogInfo("Sent InitLoginNotify!\r\n");
                }
            }

            //Client was modified, update it.
            NetworkFacade.ClientListener.UpdateClient(Client);
        }
示例#12
0
        public static void InitialClientConnect(NetworkClient Client, ProcessedPacket P)
        {
            Logger.LogInfo("Received InitialClientConnect!");

            PacketStream EncryptedPacket = new PacketStream((byte)PacketType.LOGIN_NOTIFY_CITY, 0);
            EncryptedPacket.WriteHeader();

            AESEncryptor Enc = (AESEncryptor)Client.ClientEncryptor;

            Enc.PublicKey = P.ReadBytes((P.ReadByte()));
            Enc.NOnce = P.ReadBytes((P.ReadByte()));
            Enc.PrivateKey = NetworkFacade.ServerPrivateKey;
            Client.ClientEncryptor = Enc;

            MemoryStream StreamToEncrypt = new MemoryStream();
            BinaryWriter Writer = new BinaryWriter(StreamToEncrypt);
            Writer.Write(Enc.Challenge, 0, Enc.Challenge.Length);
            Writer.Flush();

            byte[] EncryptedData = StaticStaticDiffieHellman.Encrypt(NetworkFacade.ServerPrivateKey,
                System.Security.Cryptography.ECDiffieHellmanCngPublicKey.FromByteArray(Enc.PublicKey,
                System.Security.Cryptography.CngKeyBlobFormat.EccPublicBlob), Enc.NOnce, StreamToEncrypt.ToArray());

            EncryptedPacket.WriteUInt16((ushort)(PacketHeaders.UNENCRYPTED +
                (1 + NetworkFacade.ServerPublicKey.Length) +
                (1 + EncryptedData.Length)));

            EncryptedPacket.WriteByte((byte)NetworkFacade.ServerPublicKey.Length);
            EncryptedPacket.WriteBytes(NetworkFacade.ServerPublicKey);
            EncryptedPacket.WriteByte((byte)EncryptedData.Length);
            EncryptedPacket.WriteBytes(EncryptedData);

            Client.Send(EncryptedPacket.ToArray());
        }
示例#13
0
        private void SendTickBuffer()
        {
            var ticks = new VMNetTickList { Ticks = TickBuffer };
            byte[] data;
            using (var stream = new MemoryStream())
            {
                using (var writer = new BinaryWriter(stream))
                {
                    ticks.SerializeInto(writer);
                }

                data = stream.ToArray();
            }

            using (var stream = new PacketStream((byte)PacketType.VM_PACKET, 0))
            {
                stream.WriteHeader();
                stream.WriteInt32(data.Length + (int)PacketHeaders.UNENCRYPTED);
                stream.WriteBytes(data);
                Broadcast(stream.ToArray(), ClientsToSync);
            }

            TickBuffer.Clear();
        }
示例#14
0
        private void SendState(VM vm)
        {
            if (ClientsToSync.Count == 0) return;
            //Console.WriteLine("== SERIAL: Sending State to Client... ==");

            var watch = new Stopwatch();
            watch.Start();

            var state = vm.Save();
            //Console.WriteLine("== STATE: Intermediate - after save... " + watch.ElapsedMilliseconds + " ms. ==");
            var cmd = new VMNetCommand(new VMStateSyncCmd { State = state });

            //currently just hack this on the tick system. will change when we switch to not gonzonet
            var ticks = new VMNetTickList { Ticks = new List<VMNetTick> {
                new VMNetTick {
                    Commands = new List<VMNetCommand> { cmd },
                    RandomSeed = 0, //will be restored by client from cmd
                    TickID = TickID
                }
            } };

            byte[] data;
            using (var stream = new MemoryStream())
            {
                //Console.WriteLine("== STATE: Intermediate - before serialize... " + watch.ElapsedMilliseconds + " ms. ==");
                using (var writer = new BinaryWriter(stream))
                {
                    ticks.SerializeInto(writer);
                }

                //Console.WriteLine("== STATE: Intermediate - before toArray... " + watch.ElapsedMilliseconds + " ms. ==");
                data = stream.ToArray();
            }
            //Console.WriteLine("== STATE: Intermediate - before send... " + watch.ElapsedMilliseconds + " ms. ==");

            byte[] packet;

            using (var stream = new PacketStream((byte)PacketType.VM_PACKET, 0))
            {
                stream.WriteHeader();
                stream.WriteInt32(data.Length + (int)PacketHeaders.UNENCRYPTED);
                stream.WriteBytes(data);

                packet = stream.ToArray();
            }
            foreach (var client in ClientsToSync) client.Send(packet);
            ClientsToSync.Clear();

            watch.Stop();
            //Console.WriteLine("== SERIAL: DONE! State send took "+watch.ElapsedMilliseconds+" ms. ==");
        }
示例#15
0
        /// <summary>
        /// Client created a character!
        /// </summary>
        public static void HandleCharacterCreate(NetworkClient Client, ProcessedPacket P)
        {
            Logger.LogInfo("Received CharacterCreate!");

            string AccountName = SanitizeAccount(P.ReadString());
            //Need to be variable length, because the success packet contains a token.
            PacketStream CCStatusPacket = new PacketStream((byte)PacketType.CHARACTER_CREATION_STATUS, 0);

            using (var db = DataAccess.Get())
            {
                Account Acc = db.Accounts.GetByUsername(AccountName);

                if (Acc.NumCharacters >= 3)
                {
                    CCStatusPacket.WriteByte((int)LoginDataModel.Entities.CharacterCreationStatus.ExceededCharacterLimit);
                    Client.SendEncrypted(CCStatusPacket.PacketID, CCStatusPacket.ToArray());

                    return;
                }

                //TODO: Send GUID to client...
                var Char = new Character();
                string LastCached = P.ReadString();
                if (LastCached == string.Empty)
                {
                    //TODO: Proper error...
                    CCStatusPacket.WriteByte((int)LoginDataModel.Entities.CharacterCreationStatus.NameAlreadyExisted);
                    Client.SendEncrypted(CCStatusPacket.PacketID, CCStatusPacket.ToArray());
                    return;
                }

                Char.LastCached = ProtoHelpers.ParseDateTime(LastCached);
                Char.Name = P.ReadString();
                Char.Sex = P.ReadString();
                Char.Description = P.ReadString();
                Char.GUID = Guid.NewGuid();
                Char.HeadOutfitID = (long)P.ReadUInt64();
                Char.BodyOutfitID = (long)P.ReadUInt64();
                Char.AccountID = Acc.AccountID;
                Char.AppearanceType = P.ReadByte();
                Char.CityName = P.ReadString();
                Char.CityThumb = (long)P.ReadUInt64();
                Char.City = P.ReadString();
                Char.CityMap = (long)P.ReadUInt64();
                Char.CityIp = P.ReadString();
                Char.CityPort = P.ReadInt32();
                Char.Money = NetworkFacade.INITIAL_MONEY;

                //These are going into DB, so be nazi. Sieg heil!
                if (Char.Name == string.Empty || Char.Sex == string.Empty ||
                    Char.Description == string.Empty)
                {
                    CCStatusPacket.WriteByte((int)LoginDataModel.Entities.CharacterCreationStatus.NameAlreadyExisted);
                    Client.SendEncrypted(CCStatusPacket.PacketID, CCStatusPacket.ToArray());
                    return;
                }

                var status = db.Characters.CreateCharacter(Char);

                switch (status)
                {
                    case LoginDataModel.Entities.CharacterCreationStatus.NameAlreadyExisted:
                        CCStatusPacket.WriteByte((int)LoginDataModel.Entities.CharacterCreationStatus.NameAlreadyExisted);
                        Client.SendEncrypted(CCStatusPacket.PacketID, CCStatusPacket.ToArray());
                        break;
                    case LoginDataModel.Entities.CharacterCreationStatus.NameTooLong:
                        CCStatusPacket.WriteByte((int)LoginDataModel.Entities.CharacterCreationStatus.NameTooLong);
                        Client.SendEncrypted(CCStatusPacket.PacketID, CCStatusPacket.ToArray());
                        break;
                    case LoginDataModel.Entities.CharacterCreationStatus.Success:
                        Guid Token = Guid.NewGuid();

                        //This actually updates the record, not sure how.
                        Acc.NumCharacters++;

                        //THIS NEEDS TO HAPPEN FIRST FOR CITY SERVER AUTHENTICATION TO WORK!
                        CityInfo CServer = NetworkFacade.CServerListener.GetCityServer(Char.City);

                        //Just in case...
                        if (CServer != null)
                        {
                            PacketStream CServerPacket = new PacketStream(0x01, 0);
                            CServerPacket.WriteHeader();

                            ushort PacketLength = (ushort)(PacketHeaders.UNENCRYPTED + 1 + 4 + (Client.RemoteIP.Length + 1)
                                + 4 + (Char.GUID.ToString().Length + 1) + (Token.ToString().Length + 1));
                            CServerPacket.WriteUInt16(PacketLength);

                            CServerPacket.WriteByte(1); //CharacterCreate = true
                            CServerPacket.WriteInt32(Acc.AccountID);
                            CServerPacket.WriteString(Client.RemoteIP);
                            CServerPacket.WriteInt32(Client.RemotePort);
                            CServerPacket.WriteString(Char.GUID.ToString());
                            CServerPacket.WriteString(Token.ToString(""));
                            CServer.Client.Send(CServerPacket.ToArray());
                        }

                        CCStatusPacket.WriteByte((int)LoginDataModel.Entities.CharacterCreationStatus.Success);
                        CCStatusPacket.WriteString(Char.GUID.ToString());
                        CCStatusPacket.WriteString(Token.ToString());
                        Client.SendEncrypted(CCStatusPacket.PacketID, CCStatusPacket.ToArray());

                        break;
                }
            }
        }
示例#16
0
        public static void SendLoginRequestCity(LoginArgsContainer Args)
        {
            PacketStream Packet = new PacketStream((byte)PacketType.LOGIN_REQUEST_CITY, 0);
            Packet.WriteHeader();

            //ECDiffieHellmanCng PrivateKey = Args.Client.ClientEncryptor.GetDecryptionArgsContainer()
            //    .AESDecryptArgs.PrivateKey;
            //IMPORTANT: Public key must derive from the private key!
            //byte[] ClientPublicKey = PrivateKey.PublicKey.ToByteArray();

            byte[] NOnce = Args.Client.ClientEncryptor.GetDecryptionArgsContainer().AESDecryptArgs.NOnce;

            //Packet.WriteInt32(((byte)PacketHeaders.UNENCRYPTED +
            //    (ClientPublicKey.Length + 1) + (NOnce.Length + 1)));

            //Packet.WriteByte((byte)ClientPublicKey.Length);
            //Packet.WriteBytes(ClientPublicKey);

            Packet.WriteByte((byte)NOnce.Length);
            Packet.WriteBytes(NOnce);

            Args.Client.Send(Packet.ToArray());
        }
示例#17
0
        /// <summary>
        /// Client sent a response to our challenge, as well as account name and password.
        /// </summary>
        public static void HandleChallengeResponse(NetworkClient Client, ProcessedPacket P)
        {
            PacketStream OutPacket;

            if (P.BufferLength <= 1)
            {
                OutPacket = new PacketStream((byte)PacketType.LOGIN_FAILURE, 0);
                OutPacket.WriteByte(0x03); //Bad challenge response.
                Client.Send(OutPacket.ToArray());

                Logger.LogInfo("Bad challenge response - sent SLoginFailResponse!\r\n");
                return; //How does this even happen?!
            }

            int Length = P.ReadByte();
            byte[] CResponse;

            if (P.BufferLength >= Length)
                CResponse = P.ReadBytes(Length);
            else
                return;

            AESDecryptionArgs DecryptionArgs = Client.ClientEncryptor.GetDecryptionArgsContainer().AESDecryptArgs;

            if (DecryptionArgs.Challenge.SequenceEqual(CResponse))
            {
                string AccountName = SanitizeAccount(P.ReadString());

                Length = P.ReadByte();
                byte[] PasswordHash;

                if (P.BufferLength >= Length)
                    PasswordHash = P.ReadBytes(Length);
                else
                    return;

                // Check whether the accountname is empty or is/contains "username"
                if (AccountName == string.Empty || AccountName.ToLower().Equals("username") || AccountName.ToLower().Contains("username"))
                {
                    OutPacket = new PacketStream((byte)PacketType.LOGIN_FAILURE, 0);
                    OutPacket.WriteHeader();
                    OutPacket.WriteUInt16((ushort)(PacketHeaders.UNENCRYPTED + 1));
                    OutPacket.WriteByte(0x01);
                    Client.Send(OutPacket.ToArray());

                    Logger.LogInfo(@"Bad accountname (""" + AccountName + @""") - sent SLoginFailResponse!\r\n");
                    Client.Disconnect();
                    return;
                }

                using (var db = DataAccess.Get())
                {
                    var account = db.Accounts.GetByUsername(AccountName);

                    if (!GlobalSettings.Default.CreateAccountsOnLogin)
                    {
                        Logger.LogInfo("Done reading LoginRequest, checking account...\r\n");

                        if (account == null)
                        {
                            OutPacket = new PacketStream((byte)PacketType.LOGIN_FAILURE, 0);
                            OutPacket.WriteHeader();
                            OutPacket.WriteUInt16((ushort)(PacketHeaders.UNENCRYPTED + 1));
                            OutPacket.WriteByte(0x01);
                            Client.Send(OutPacket.ToArray());

                            Logger.LogInfo(@"Bad accountname (""" + AccountName + @""") - sent SLoginFailResponse!\r\n");
                            Client.Disconnect();
                            return;
                        }
                    }
                    else
                    {
                        if (account == null)
                        {
                            try
                            {
                                if (!AccountName.ToLower().Equals("username") || !AccountName.ToLower().Contains("username"))
                                db.Accounts.Create(new Account
                                {
                                    AccountName = AccountName.ToLower(),
                                    Password = Convert.ToBase64String(PasswordHash)
                                });
                            }
                            catch (Exception)
                            {
                                OutPacket = new PacketStream((byte)PacketType.LOGIN_FAILURE, 0);
                                OutPacket.WriteHeader();
                                OutPacket.WriteUInt16((ushort)(PacketHeaders.UNENCRYPTED + 1));
                                OutPacket.WriteByte(0x01);
                                Client.Send(OutPacket.ToArray());

                                Logger.LogInfo(@"Bad accountname (""" + AccountName + @""") - sent SLoginFailResponse!\r\n");
                                Client.Disconnect();
                                return;
                            }

                            account = db.Accounts.GetByUsername(AccountName);
                        }
                    }

                    if (account.IsCorrectPassword(AccountName, PasswordHash))
                    {
                        OutPacket = new PacketStream((byte)PacketType.LOGIN_SUCCESS, 0);
                        OutPacket.WriteByte(0x01);
                        Client.ClientEncryptor.Username = AccountName;
                        Client.SendEncrypted((byte)PacketType.LOGIN_SUCCESS, OutPacket.ToArray());

                        Logger.LogInfo("Sent SLoginSuccessResponse!\r\n");
                        return;
                    }
                    else
                    {
                        OutPacket = new PacketStream((byte)PacketType.LOGIN_FAILURE, 0);
                        OutPacket.WriteHeader();
                        OutPacket.WriteUInt16((ushort)(PacketHeaders.UNENCRYPTED + 1));
                        OutPacket.WriteByte(0x02);
                        Client.Send(OutPacket.ToArray());

                        Logger.LogInfo("Bad password - sent SLoginFailResponse!\r\n");
                        Client.Disconnect();
                        return;
                    }
                }
            }

            OutPacket = new PacketStream((byte)PacketType.LOGIN_FAILURE, 0);
            OutPacket.WriteHeader();
            OutPacket.WriteUInt16((ushort)(PacketHeaders.UNENCRYPTED + 1));
            OutPacket.WriteByte(0x03); //Bad challenge response.
            Client.Send(OutPacket.ToArray());

            Logger.LogInfo("Bad challenge response - sent SLoginFailResponse!\r\n");
            return;
        }
        public static void HandleCityTokenRequest(NetworkClient Client, ProcessedPacket P)
        {
            string AccountName = P.ReadPascalString();
            string CityGUID = P.ReadPascalString();
            string CharGUID = P.ReadPascalString();
            string Token = new Guid().ToString();

            foreach (CityServerClient CServer in NetworkFacade.CServerListener.CityServers)
            {
                if (CityGUID == CServer.ServerInfo.UUID)
                {
                    using (var db = DataAccess.Get())
                    {
                        Account Acc = db.Accounts.GetByUsername(AccountName);

                        PacketStream CServerPacket = new PacketStream(0x01, 0);
                        CServerPacket.WriteHeader();

                        ushort PacketLength = (ushort)(PacketHeaders.UNENCRYPTED + 4 + (Client.RemoteIP.Length + 1)
                            + (CharGUID.ToString().Length + 1) + (Token.ToString().Length + 1));
                        CServerPacket.WriteUInt16(PacketLength);

                        CServerPacket.WriteInt32(Acc.AccountID);
                        CServerPacket.WritePascalString(Client.RemoteIP);
                        CServerPacket.WritePascalString(CharGUID.ToString());
                        CServerPacket.WritePascalString(Token.ToString());
                        CServer.Send(CServerPacket.ToArray());

                        break;
                    }
                }
            }

            PacketStream Packet = new PacketStream((byte)PacketType.REQUEST_CITY_TOKEN, 0);
            Packet.WritePascalString(Token);
            Client.SendEncrypted((byte)PacketType.REQUEST_CITY_TOKEN, Packet.ToArray());
        }
示例#19
0
        /// <summary>
        /// Client wanted to transfer to a city server.
        /// </summary>
        public static void HandleCityTokenRequest(NetworkClient Client, ProcessedPacket P)
        {
            string AccountName = P.ReadString();
            string CityGUID = P.ReadString();
            string CharGUID = P.ReadString();

            if (AccountName == string.Empty || CityGUID == string.Empty || CharGUID == string.Empty)
                return;

            Guid Token = Guid.NewGuid();
            CityInfo CServer = NetworkFacade.CServerListener.GetCityServer(CityGUID);

            using (var db = DataAccess.Get())
            {
                Account Acc = db.Accounts.GetByUsername(AccountName);

                PacketStream CServerPacket = new PacketStream(0x01, 0);
                CServerPacket.WriteHeader();

                ushort PacketLength = (ushort)(PacketHeaders.UNENCRYPTED + 1 + 4 + (Client.RemoteIP.Length + 1)
                    + 4 + (CharGUID.ToString().Length + 1) + (Token.ToString().Length + 1));
                CServerPacket.WriteUInt16(PacketLength);

                CServerPacket.WriteByte(0); //CharacterCreate = false.
                CServerPacket.WriteInt32(Acc.AccountID);
                CServerPacket.WriteString(Client.RemoteIP);
                CServerPacket.WriteInt32(Client.RemotePort);
                CServerPacket.WriteString(CharGUID.ToString());
                CServerPacket.WriteString(Token.ToString(""));
                CServer.Client.Send(CServerPacket.ToArray());
            }
        }
        public static void HandleCharacterCreate(NetworkClient Client, ProcessedPacket P)
        {
            Logger.LogInfo("Received CharacterCreate!");

            string AccountName = SanitizeAccount(P.ReadPascalString());

            using (var db = DataAccess.Get())
            {
                Account Acc = db.Accounts.GetByUsername(AccountName);

                //TODO: Send GUID to client...
                SimBase Char = new SimBase(Guid.NewGuid());
                Char.Timestamp = P.ReadPascalString();
                Char.Name = P.ReadPascalString();
                Char.Sex = P.ReadPascalString();
                Char.Description = P.ReadPascalString();
                Char.HeadOutfitID = P.ReadUInt64();
                Char.BodyOutfitID = P.ReadUInt64();
                Char.Appearance = (AppearanceType)P.ReadByte();
                Char.ResidingCity = new CityInfo(P.ReadPascalString(), "", P.ReadUInt64(), P.ReadPascalString(),
                    P.ReadUInt64(), P.ReadPascalString(), P.ReadInt32());
                Char.CreatedThisSession = true;

                var characterModel = new Character();
                characterModel.Name = Char.Name;
                characterModel.Sex = Char.Sex;
                characterModel.Description = Char.Description;
                characterModel.LastCached = Char.Timestamp;
                characterModel.GUID = Char.GUID;
                characterModel.HeadOutfitID = (long)Char.HeadOutfitID;
                characterModel.BodyOutfitID = (long)Char.BodyOutfitID;
                characterModel.AccountID = Acc.AccountID;
                characterModel.AppearanceType = (int)Char.Appearance;
                characterModel.City = Char.ResidingCity.UUID;
                characterModel.CityName = Char.ResidingCity.Name;
                characterModel.CityThumb = (long)Char.ResidingCity.Thumbnail;
                characterModel.CityMap = (long)Char.ResidingCity.Map;
                characterModel.CityIp = Char.ResidingCity.IP;
                characterModel.CityPort = Char.ResidingCity.Port;

                var status = db.Characters.CreateCharacter(characterModel);
                //Need to be variable length, because the success packet contains a token.
                PacketStream CCStatusPacket = new PacketStream((byte)PacketType.CHARACTER_CREATION_STATUS, 0);

                switch (status)
                {
                    case LoginDataModel.Entities.CharacterCreationStatus.NameAlreadyExisted:
                        CCStatusPacket.WriteByte((int)LoginDataModel.Entities.CharacterCreationStatus.NameAlreadyExisted);
                        Client.SendEncrypted(CCStatusPacket.PacketID, CCStatusPacket.ToArray());
                        break;
                    case LoginDataModel.Entities.CharacterCreationStatus.ExceededCharacterLimit:
                        CCStatusPacket.WriteByte((int)LoginDataModel.Entities.CharacterCreationStatus.ExceededCharacterLimit);
                        Client.SendEncrypted(CCStatusPacket.PacketID, CCStatusPacket.ToArray());
                        break;
                    case LoginDataModel.Entities.CharacterCreationStatus.Success:
                        CCStatusPacket.WriteByte((int)LoginDataModel.Entities.CharacterCreationStatus.Success);
                        CCStatusPacket.WritePascalString(Char.GUID.ToString());
                        Guid Token = Guid.NewGuid();
                        CCStatusPacket.WritePascalString(Token.ToString());
                        Client.SendEncrypted(CCStatusPacket.PacketID, CCStatusPacket.ToArray());

                        foreach (CityServerClient CServer in NetworkFacade.CServerListener.CityServers)
                        {
                            if (CServer.ServerInfo.UUID == Char.ResidingCity.UUID)
                            {
                                PacketStream CServerPacket = new PacketStream(0x01, 0);
                                CServerPacket.WriteHeader();

                                ushort PacketLength = (ushort)(PacketHeaders.UNENCRYPTED + 4 + (Client.RemoteIP.Length + 1)
                                    + (Char.GUID.ToString().Length + 1) + (Token.ToString().Length + 1));
                                CServerPacket.WriteUInt16(PacketLength);

                                CServerPacket.WriteInt32(Acc.AccountID);
                                CServerPacket.WritePascalString(Client.RemoteIP);
                                CServerPacket.WritePascalString(Char.GUID.ToString());
                                CServerPacket.WritePascalString(Token.ToString());
                                CServer.Send(CServerPacket.ToArray());

                                break;
                            }
                        }

                        break;
                }
            }

            //Client was modified, so update it.
            NetworkFacade.ClientListener.UpdateClient(Client);
        }
示例#21
0
 private void SendToServer(VMNetCommandBodyAbstract cmd)
 {
     byte[] data;
     using (var stream = new MemoryStream())
     {
         var cmd2 = new VMNetCommand(cmd);
         using (var writer = new BinaryWriter(stream))
         {
             cmd2.SerializeInto(writer);
         }
         data = stream.ToArray();
     }
     using (var stream = new PacketStream((byte)PacketType.VM_PACKET, 0))
     {
         stream.WriteHeader();
         stream.WriteInt32(data.Length + (int)PacketHeaders.UNENCRYPTED);
         stream.WriteBytes(data);
         Client.Send(stream.ToArray());
     }
 }
示例#22
0
        private void SendState(VM vm)
        {
            if (ClientsToSync.Count == 0) return;
            var state = vm.Save();
            var cmd = new VMNetCommand(new VMStateSyncCmd { State = state });

            //currently just hack this on the tick system. will change when we switch to not gonzonet
            var ticks = new VMNetTickList { Ticks = new List<VMNetTick> {
                new VMNetTick {
                    Commands = new List<VMNetCommand> { cmd },
                    RandomSeed = 0, //will be restored by client from cmd
                    TickID = TickID
                }
            } };

            byte[] data;
            using (var stream = new MemoryStream())
            {
                using (var writer = new BinaryWriter(stream))
                {
                    ticks.SerializeInto(writer);
                }

                data = stream.ToArray();
            }

            using (var stream = new PacketStream((byte)PacketType.VM_PACKET, 0))
            {
                stream.WriteHeader();
                stream.WriteInt32(data.Length + (int)PacketHeaders.UNENCRYPTED);
                stream.WriteBytes(data);

                var packet = stream.ToArray();

                foreach (var client in ClientsToSync) client.Send(packet);
            }
            ClientsToSync.Clear();
        }