public static bool IsForbidden(string text, out string forbiddenWord)
        {
            forbiddenWord = string.Empty;
            if (forbiddenWords == null)
            {
                return false;
            }

            char[] delimiters = new char[] { ' ', '-', '.', '_', ':', ';', '\'' };

            HashSet<string> words = new HashSet<string>();
            foreach (char delimiter in delimiters)
            {
                foreach (string word in text.Split(delimiter))
                {
                    words.Add(word);
                }
            }

            foreach (string word in words)
            {
                if (forbiddenWords.Any(w => Homoglyphs.Compare(word, w)))
                {
                    forbiddenWord = word;
                    return true;
                }
            }
            return false;
        }
예제 #2
0
        private void ClientInitRequest(NetIncomingMessage inc)
        {
            Boolean isNilModClient = false;

            if (ConnectedClients.Find(c => c.Connection == inc.SenderConnection) != null)
            {
                //this client was already authenticated
                //another init request means they didn't get any update packets yet
                return;
            }

            UnauthenticatedClient unauthClient = unauthenticatedClients.Find(uc => uc.Connection == inc.SenderConnection);

            if (unauthClient == null)
            {
                //client did not ask for nonce first, can't authorize
                inc.SenderConnection.Disconnect("Client (" + unauthClient.Connection.RemoteEndPoint.Address.ToString() + ") did not properly request authentication.");
                return;
            }

            if (!string.IsNullOrEmpty(password))
            {
                //decrypt message and compare password
                string saltedPw = password;
                saltedPw = saltedPw + Convert.ToString(unauthClient.Nonce);
                saltedPw = Encoding.UTF8.GetString(NetUtility.ComputeSHAHash(Encoding.UTF8.GetBytes(saltedPw)));
                string clPw = inc.ReadString();
                if (clPw != saltedPw)
                {
                    unauthClient.failedAttempts++;
                    if (unauthClient.failedAttempts > 3)
                    {
                        //disconnect and ban after too many failed attempts
                        banList.BanPlayer("PASSWORDBAN", unauthClient.Connection.RemoteEndPoint.Address.ToString(), "Too many failed login attempts.", null);
                        DisconnectUnauthClient(inc, unauthClient, "Too many failed login attempts. You have been automatically banned from the server.");

                        Log(inc.SenderConnection.RemoteEndPoint.Address.ToString() + " has been banned from the server (too many wrong passwords)", ServerLog.MessageType.Error);
                        DebugConsole.NewMessage(inc.SenderConnection.RemoteEndPoint.Address.ToString() + " has been banned from the server (too many wrong passwords)", Color.Red);
                        GameServer.LogToClientconsole(inc.SenderConnection.RemoteEndPoint.Address.ToString() + " has been banned from the server (too many wrong passwords)");
                        return;
                    }
                    else
                    {
                        //not disconnecting the player here, because they'll still use the same connection and nonce if they try logging in again
                        NetOutgoingMessage reject = server.CreateMessage();
                        reject.Write((byte)ServerPacketHeader.AUTH_FAILURE);
                        reject.Write("Wrong password! You have " + Convert.ToString(4 - unauthClient.failedAttempts) + " more attempts before you're banned from the server.");
                        Log(inc.SenderConnection.RemoteEndPoint.Address.ToString() + " failed to join the server (incorrect password)", ServerLog.MessageType.Error);
                        DebugConsole.NewMessage(inc.SenderConnection.RemoteEndPoint.Address.ToString() + " failed to join the server (incorrect password)", Color.Red);
                        GameServer.LogToClientconsole(inc.SenderConnection.RemoteEndPoint.Address.ToString() + " failed to join the server (incorrect password)");
                        server.SendMessage(reject, unauthClient.Connection, NetDeliveryMethod.Unreliable);
                        unauthClient.AuthTimer = 10.0f;
                        return;
                    }
                }
            }
            string clVersion     = inc.ReadString();
            string clPackageName = inc.ReadString();
            string clPackageHash = inc.ReadString();

            string clName = Client.SanitizeName(inc.ReadString());

            if (string.IsNullOrWhiteSpace(clName))
            {
                DisconnectUnauthClient(inc, unauthClient, "You need a name.");

                Log(inc.SenderConnection.RemoteEndPoint.Address.ToString() + " couldn't join the server (no name given)", ServerLog.MessageType.Connection);
                DebugConsole.NewMessage(inc.SenderConnection.RemoteEndPoint.Address.ToString() + " couldn't join the server (no name given)", Color.Red);
                GameServer.LogToClientconsole(inc.SenderConnection.RemoteEndPoint.Address.ToString() + " couldn't join the server (no name given)");
                return;
            }

            if (clVersion != GameMain.Version.ToString())
            {
                DisconnectUnauthClient(inc, unauthClient, "Version " + GameMain.Version + " required to connect to the server (Your version: " + clVersion + ")");

                Log(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (wrong game version) - CLVersion: " + clVersion + " vs servers " + GameMain.Version, ServerLog.MessageType.Connection);
                DebugConsole.NewMessage(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (wrong game version) - CLVersion: " + clVersion + " vs servers " + GameMain.Version, Color.Red);
                GameServer.LogToClientconsole(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (wrong game version) - CLVersion: " + clVersion + " vs servers " + GameMain.Version);
                return;
            }
            if (clPackageName != GameMain.SelectedPackage.Name)
            {
                DisconnectUnauthClient(inc, unauthClient, "Your content package (" + clPackageName + ") doesn't match the server's version (" + GameMain.SelectedPackage.Name + ")");
                Log(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server with Incorrect Content Package: (" + clPackageName + ") vs servers (" + GameMain.SelectedPackage.Name + ")", ServerLog.MessageType.Connection);
                DebugConsole.NewMessage(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server with Incorrect Content Package: (" + clPackageName + ") vs servers (" + GameMain.SelectedPackage.Name + ")", Color.Red);
                GameServer.LogToClientconsole(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server with Incorrect Content Package: (" + clPackageName + ") vs servers (" + GameMain.SelectedPackage.Name + ")");
                return;
            }

            if (clPackageHash.Substring(0, 7).Contains("NILMOD_"))
            {
                if (!GameMain.NilMod.AllowNilModClients)
                {
                    DisconnectUnauthClient(inc, unauthClient, "This server does not permit Nilmod clients (Please rejoin using Vanilla).");
                    Log(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (Nilmod clients are not permitted to connect).", ServerLog.MessageType.Connection);
                    DebugConsole.NewMessage(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (Nilmod clients are not permitted to connect).", Color.Red);
                    GameServer.LogToClientconsole(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (Nilmod clients are not permitted to connect).");
                    return;
                }
                else
                {
                    isNilModClient = true;
                    clPackageHash  = clPackageHash.Substring(7);
                }
            }
            else
            {
                if (!GameMain.NilMod.AllowVanillaClients)
                {
                    DisconnectUnauthClient(inc, unauthClient, "This server does not permit Vanilla clients (Please rejoin using Nilmod).");
                    Log(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (Vanilla clients are not permitted to connect).", ServerLog.MessageType.Connection);
                    DebugConsole.NewMessage(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (Vanilla clients are not permitted to connect).", Color.Red);
                    GameServer.LogToClientconsole(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (Vanilla clients are not permitted to connect).");
                    return;
                }
            }

            if (GameMain.NilMod.BypassMD5 == true)
            {
                if (clPackageHash != GameMain.NilMod.ServerMD5A && clPackageHash != GameMain.NilMod.ServerMD5B)
                {
                    DisconnectUnauthClient(inc, unauthClient, "Your content package (MD5: " + clPackageHash + ") doesn't match the server's version (MD5: " + GameMain.NilMod.ServerMD5A + ")");
                    Log(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (wrong content package hash) MD5: (" + clPackageHash + ") vs servers MD5A: (" + GameMain.NilMod.ServerMD5A + "), MD5B: (" + GameMain.NilMod.ServerMD5B + ")", ServerLog.MessageType.Connection);
                    DebugConsole.NewMessage(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (wrong content package hash):" + clPackageHash + " vs servers " + GameMain.NilMod.ServerMD5A + ", (" + GameMain.NilMod.ServerMD5B + ")", Color.Red);
                    GameServer.LogToClientconsole(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (wrong content package hash):" + clPackageHash + " vs servers " + GameMain.NilMod.ServerMD5A + ", (" + GameMain.NilMod.ServerMD5B + ")");
                    return;
                }
            }
            else
            {
                if (clPackageHash != GameMain.SelectedPackage.MD5hash.Hash)
                {
                    DisconnectUnauthClient(inc, unauthClient, "Your content package (MD5: " + clPackageHash + ") doesn't match the server's version (MD5: " + GameMain.SelectedPackage.MD5hash.Hash + ")");
                    Log(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (wrong content package hash)", ServerLog.MessageType.Connection);
                    DebugConsole.NewMessage(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (wrong content package hash)", Color.Red);
                    GameServer.LogToClientconsole(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (wrong content package hash)");
                    return;
                }
            }

            if (!whitelist.IsWhiteListed(clName, inc.SenderConnection.RemoteEndPoint.Address.ToString()))
            {
                DisconnectUnauthClient(inc, unauthClient, "You're not in this server's whitelist.");
                Log(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (not in whitelist)", ServerLog.MessageType.Connection);
                DebugConsole.NewMessage(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (not in whitelist)", Color.Red);
                GameServer.LogToClientconsole(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (not in whitelist)");
                return;
            }
            if (GameMain.NilMod.MinimumNameLength > clName.Length)
            {
                DisconnectUnauthClient(inc, unauthClient, "Your name is too short, Minimum length on this server is " + GameMain.NilMod.MinimumNameLength + " characters.");
                Log(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (name too short)", ServerLog.MessageType.Connection);
                DebugConsole.NewMessage(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (name too short, minimum length is " + GameMain.NilMod.MinimumNameLength + " characters)", Color.Red);
                GameServer.LogToClientconsole(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (name too short, minimum length is " + GameMain.NilMod.MinimumNameLength + " characters)");
                return;
            }
            if (!Client.IsValidName(clName))
            {
                DisconnectUnauthClient(inc, unauthClient, "Your name contains illegal symbols.");
                Log(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (invalid name)", ServerLog.MessageType.Connection);
                DebugConsole.NewMessage(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (invalid name)", Color.Red);
                GameServer.LogToClientconsole(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (invalid name)");
                return;
            }

            if (!GameMain.NilMod.AllowCyrillicText && Regex.IsMatch(clName, @"\p{IsCyrillic}"))
            {
                DisconnectUnauthClient(inc, unauthClient, "This server does not allow Cyrillic alphabets.");
                Log(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (Name contains cyrillic characters)", ServerLog.MessageType.Connection);
                DebugConsole.NewMessage(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (Name contains cyrillic characters)", Color.Red);
                GameServer.LogToClientconsole(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (Name contains cyrillic characters)");
                return;
            }

            if (!GameMain.NilMod.AllowEnglishText && Regex.IsMatch(clName, "^[a-zA-Z]*$"))
            {
                DisconnectUnauthClient(inc, unauthClient, "This server does not allow English alphabets.");
                Log(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (Name contains english characters)", ServerLog.MessageType.Connection);
                DebugConsole.NewMessage(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (Name contains english characters)", Color.Red);
                GameServer.LogToClientconsole(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (Name contains english characters)");
                return;
            }

            //Nilmod prevent players rejoining as server hosts current name OR server name.
            if (Homoglyphs.Compare(clName.ToLower(), Name.ToLower()) || Homoglyphs.Compare(clName.ToLower(), GameMain.NilMod.PlayYourselfName.ToLower()) || Homoglyphs.Compare(clName.ToLower(), NilMod.NilModGriefWatcher.GriefWatchName))
            {
                DisconnectUnauthClient(inc, unauthClient, "That name is taken by the server.");
                Log(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (name taken by the server)", ServerLog.MessageType.Connection);
                DebugConsole.NewMessage(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (name taken by the server)", Color.Red);
                GameServer.LogToClientconsole(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (name taken by the server)");
                return;
            }
            Client nameTaken = ConnectedClients.Find(c => Homoglyphs.Compare(c.Name.ToLower(), clName.ToLower()));

            if (nameTaken != null)
            {
                if (nameTaken.Connection.RemoteEndPoint.Address.ToString() == inc.SenderEndPoint.Address.ToString())
                {
                    //both name and IP address match, replace this player's connection
                    nameTaken.Connection.Disconnect("Your session was taken by a new connection on the same IP address.");
                    nameTaken.Connection = unauthClient.Connection;
                    nameTaken.InitClientSync(); //reinitialize sync ids because this is a new connection
                    unauthenticatedClients.Remove(unauthClient);
                    unauthClient = null;
                    return;
                }
                else
                {
                    //can't authorize this client
                    DisconnectUnauthClient(inc, unauthClient, "That name is taken.");
                    Log(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (name already taken)", ServerLog.MessageType.Connection);
                    DebugConsole.NewMessage(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (name already taken)", Color.Red);
                    GameServer.LogToClientconsole(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (name already taken)");
                    return;
                }
            }

            //MaxIdenticalIPConnections
            List <Client> SimilarIP = ConnectedClients.FindAll(c => c.Connection.RemoteEndPoint.Address.ToString() == inc.SenderConnection.RemoteEndPoint.Address.ToString());

            if (SimilarIP.Count >= GameMain.NilMod.MaxIdenticalIPConnections)
            {
                //can't authorize this client
                DisconnectUnauthClient(inc, unauthClient, "Too many similar IPs are on the server, max is " + GameMain.NilMod.MaxIdenticalIPConnections);
                Log(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (Max Identical IP Connections exceeded)", ServerLog.MessageType.Connection);
                DebugConsole.NewMessage(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (Max Identical IP Connections exceeded, max is " + GameMain.NilMod.MaxIdenticalIPConnections + ")", Color.Red);
                GameServer.LogToClientconsole(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (Max Identical IP Connections exceeded, max is " + GameMain.NilMod.MaxIdenticalIPConnections + ")");
                return;
            }

            KickedClient kickedclient = null;

            if (GameMain.NilMod.KickedClients.Count > 0)
            {
                for (int i = GameMain.NilMod.KickedClients.Count - 1; i >= 0; i--)
                {
                    if (GameMain.NilMod.KickedClients[i].IPAddress == unauthClient.Connection.RemoteEndPoint.Address.ToString())
                    {
                        if (GameMain.NilMod.KickedClients[i].RejoinTimer > 0f)
                        {
                            DisconnectUnauthClient(inc, unauthClient, "You have been kicked for " + ToolBox.SecondsToReadableTime(GameMain.NilMod.KickedClients[i].RejoinTimer) + ".\n" + GameMain.NilMod.KickedClients[i].KickReason.Replace("You have been kicked from the server.", ""));
                            return;
                        }
                        else
                        {
                            kickedclient = GameMain.NilMod.KickedClients[i];
                        }
                    }
                }
            }

            if (banList.IsBanned(inc.SenderEndPoint.Address.ToString()))
            {
                if (GameMain.NilMod.EnablePlayerLogSystem)
                {
                    DebugConsole.NewMessage("Banned Player tried to join the server (" + inc.SenderEndPoint.Address.ToString() + " - " + clName.ToString() + ")" + NilMod.NilModPlayerLog.ListPrevious(inc.SenderConnection.RemoteEndPoint.Address.ToString(), clName, false, true, false), Color.Red);
                    ServerLog.WriteLine("Banned Player tried to join the server (" + inc.SenderEndPoint.Address.ToString() + " - " + clName.ToString() + ")" + NilMod.NilModPlayerLog.ListPrevious(inc.SenderConnection.RemoteEndPoint.Address.ToString(), clName, false, true, false), ServerLog.MessageType.Connection);
                    GameServer.LogToClientconsole("Banned Player tried to join the server (" + inc.SenderEndPoint.Address.ToString() + " - " + clName.ToString() + ")" + NilMod.NilModPlayerLog.ListPrevious(inc.SenderConnection.RemoteEndPoint.Address.ToString(), clName, false, true, false));
                }
                else
                {
                    DebugConsole.NewMessage("Banned Player tried to join the server (" + inc.SenderEndPoint.Address.ToString() + " - " + clName.ToString() + ")", Color.Red);
                    ServerLog.WriteLine("Banned Player tried to join the server (" + inc.SenderEndPoint.Address.ToString() + " - " + clName.ToString() + ")", ServerLog.MessageType.Connection);
                    GameServer.LogToClientconsole("Banned Player tried to join the server (" + inc.SenderEndPoint.Address.ToString() + " - " + clName.ToString() + ")");
                }
                string banText = "";

                if (GameMain.NilMod.BansInfoAddBanName)
                {
                    banText = "You've been banned as '" + banList.GetBanName(inc.SenderEndPoint.Address.ToString()) + "'.";
                }
                else
                {
                    banText = "You've been banned from the server.";
                }

                //Add Ban duration text
                if (banList.GetBanExpiry(inc.SenderEndPoint.Address.ToString()) != null && GameMain.NilMod.BansInfoAddBanDuration)
                {
                    if (GameMain.NilMod.BansInfoUseRemainingTime)
                    {
                        TimeSpan banRemaining = Convert.ToDateTime(banList.GetBanExpiry(inc.SenderEndPoint.Address.ToString())).Subtract(DateTime.Now);

                        banText += "\n" + "Expires in: ";
                        if (banRemaining.Days > 0)
                        {
                            banText += banRemaining.Days + " Days, ";
                        }
                        if (banRemaining.Hours > 0)
                        {
                            banText += banRemaining.Hours + " Hours, ";
                        }
                        if (banRemaining.Minutes > 0)
                        {
                            banText += banRemaining.Minutes + " Minutes, ";
                        }

                        banText = banText.Substring(0, banText.Length - 2);
                    }
                    else
                    {
                        banText += "\n" + "Expire on: " + banList.GetBanExpiry(inc.SenderEndPoint.Address.ToString())
                                   + "\n" + "Currently: " + DateTime.Now.ToString();
                    }
                }
                //Permanent ban text
                else if (banList.GetBanExpiry(inc.SenderEndPoint.Address.ToString()) == null && GameMain.NilMod.BansInfoAddBanDuration)
                {
                    if (GameMain.NilMod.BansInfoAddBanName)
                    {
                        banText = "You've been permanently banned as '" + banList.GetBanName(inc.SenderEndPoint.Address.ToString()) + "'";
                    }
                    else
                    {
                        banText = "You've been permanently banned from the server.";
                    }
                }

                if (GameMain.NilMod.BansInfoAddCustomString)
                {
                    banText += "\n" + GameMain.NilMod.BansInfoCustomtext;
                }

                if (GameMain.NilMod.BansInfoAddBanReason)
                {
                    banText += "\n" + "for:" + banList.GetBanReason(inc.SenderEndPoint.Address.ToString());
                }

                DisconnectUnauthClient(inc, unauthClient, banText);

                /*
                 *  if (banList.GetBanExpiry(inc.SenderEndPoint.Address.ToString()) != null)
                 * {
                 *  //None Permament Ban
                 *  DisconnectUnauthClient(inc, unauthClient, "You have been banned As '" + banList.GetBanName(inc.SenderEndPoint.Address.ToString())
                 + "' with reason: " + banList.GetBanReason(inc.SenderEndPoint.Address.ToString())
                 + " \n Expires On: " + banList.GetBanExpiry(inc.SenderEndPoint.Address.ToString())
                 + " (Currently: " + DateTime.Now.ToString()
                 + "). \n" + "Appeal at www.barotraumaserver.com");
                 + }
                 + else
                 + {
                 +  //Permanent ban
                 +  DisconnectUnauthClient(inc, unauthClient, "You have been banned As '" + banList.GetBanName(inc.SenderEndPoint.Address.ToString()) + "' with reason: " + banList.GetBanReason(inc.SenderEndPoint.Address.ToString()) + "\n" + " \n This ban is permanent. \n" + "Appeal at Blabla (Custom text here)! \n \n \n \n \n \n.");
                 + }
                 */
                return;
            }

            //new client
            Client newClient = new Client(clName, GetNewClientID());

            newClient.IsNilModClient        = isNilModClient;
            newClient.RequiresNilModSync    = isNilModClient;
            newClient.NilModSyncResendTimer = 4f;
            newClient.InitClientSync();
            newClient.Connection = unauthClient.Connection;
            unauthenticatedClients.Remove(unauthClient);
            unauthClient = null;

            SavedClientPermission savedPermissions = clientPermissions.Find(cp => cp.IP == newClient.Connection.RemoteEndPoint.Address.ToString());

            if (savedPermissions == null)
            {
                savedPermissions = defaultpermission;
            }

            newClient.OwnerSlot         = savedPermissions.OwnerSlot;
            newClient.AdministratorSlot = savedPermissions.AdministratorSlot;
            newClient.TrustedSlot       = savedPermissions.TrustedSlot;

            newClient.AllowInGamePM           = savedPermissions.AllowInGamePM;
            newClient.GlobalChatSend          = savedPermissions.GlobalChatSend;
            newClient.GlobalChatReceive       = savedPermissions.GlobalChatReceive;
            newClient.KarmaImmunity           = savedPermissions.KarmaImmunity;
            newClient.BypassSkillRequirements = savedPermissions.BypassSkillRequirements;
            newClient.PrioritizeJob           = savedPermissions.PrioritizeJob;
            newClient.IgnoreJobMinimum        = savedPermissions.IgnoreJobMinimum;
            newClient.KickImmunity            = savedPermissions.KickImmunity;
            newClient.BanImmunity             = savedPermissions.BanImmunity;

            newClient.HideJoin              = savedPermissions.HideJoin;
            newClient.AccessDeathChatAlive  = savedPermissions.AccessDeathChatAlive;
            newClient.AdminPrivateMessage   = savedPermissions.AdminPrivateMessage;
            newClient.AdminChannelSend      = savedPermissions.AdminChannelSend;
            newClient.AdminChannelReceive   = savedPermissions.AdminChannelReceive;
            newClient.SendServerConsoleInfo = savedPermissions.SendServerConsoleInfo;
            newClient.CanBroadcast          = savedPermissions.CanBroadcast;

            newClient.SetPermissions(savedPermissions.Permissions, savedPermissions.PermittedCommands);

            ConnectedClients.Add(newClient);

#if CLIENT
            GameSession.inGameInfo.AddClient(newClient);
            GameMain.NetLobbyScreen.AddPlayer(newClient.Name);
#endif
            if (GameMain.NilMod.EnableVPNBanlist)
            {
                CoroutineManager.StartCoroutine(NilMod.NilModVPNBanlist.CheckVPNBan(newClient, clName.ToString()), "NilModVPNBanlist");
            }

            if (!GameMain.NilMod.EnableVPNBanlist)
            {
                if (GameMain.NilMod.EnablePlayerLogSystem)
                {
                    if (!newClient.HideJoin)
                    {
                        GameMain.Server.SendChatMessage(NilMod.NilModPlayerLog.ListPrevious(inc.SenderConnection.RemoteEndPoint.Address.ToString(), clName, false, false, true), ChatMessageType.Server, null);
                    }
                    DebugConsole.NewMessage(NilMod.NilModPlayerLog.ListPrevious(inc.SenderConnection.RemoteEndPoint.Address.ToString(), clName, true, true, true), Color.White);
                    Log(NilMod.NilModPlayerLog.ListPrevious(inc.SenderConnection.RemoteEndPoint.Address.ToString(), clName, true, true, true), ServerLog.MessageType.Connection);
                    GameServer.LogToClientconsole(NilMod.NilModPlayerLog.ListPrevious(inc.SenderConnection.RemoteEndPoint.Address.ToString(), clName, true, true, true));

                    NilMod.NilModPlayerLog.LogPlayer(inc.SenderConnection.RemoteEndPoint.Address.ToString(), clName);
                }
                else
                {
                    DisconnectedCharacter ReconnectedClient = null;

                    if (GameMain.NilMod.DisconnectedCharacters.Count > 0)
                    {
                        ReconnectedClient = GameMain.NilMod.DisconnectedCharacters.Find(dc => dc.IPAddress == inc.SenderConnection.RemoteEndPoint.Address.ToString() && dc.clientname == clName);
                    }

                    if (kickedclient != null)
                    {
                        GameMain.Server.SendChatMessage("Recently Kicked Player " + clName + " (" + kickedclient.clientname + ") has rejoined the server.", ChatMessageType.Server, null);
                        DebugConsole.NewMessage("Recently Kicked Player " + clName + " (" + kickedclient.clientname + ") (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") has joined the server.", Color.White);
                        Log("Recently Kicked Player " + clName + " (" + kickedclient.clientname + ") (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") has joined the server.", ServerLog.MessageType.Connection);
                        GameServer.LogToClientconsole("Recently Kicked Player " + clName + " (" + kickedclient.clientname + ") (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") has joined the server.");

                        if (GameMain.NilMod.ClearKickStateNameOnRejoin)
                        {
                            GameMain.NilMod.KickedClients.Remove(kickedclient);
                        }
                        else
                        {
                            kickedclient.ExpireTimer += GameMain.NilMod.KickStateNameTimerIncreaseOnRejoin;
                            if (kickedclient.ExpireTimer > GameMain.NilMod.KickMaxStateNameTimer)
                            {
                                kickedclient.ExpireTimer = GameMain.NilMod.KickMaxStateNameTimer;
                            }
                        }
                    }
                    else if (ReconnectedClient == null)
                    {
                        if (!newClient.HideJoin)
                        {
                            GameMain.Server.SendChatMessage(clName + " has joined the server.", ChatMessageType.Server, null);
                        }
                        DebugConsole.NewMessage(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") has joined the server.", Color.White);
                        Log(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") has joined the server.", ServerLog.MessageType.Connection);
                        GameServer.LogToClientconsole(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") has joined the server.");
                    }
                    else
                    {
                        if (!newClient.HideJoin)
                        {
                            GameMain.Server.SendChatMessage(clName + " has reconnected to the server.", ChatMessageType.Server, null);
                        }
                        DebugConsole.NewMessage(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") has reconnected to the server.", Color.White);
                        Log(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") has reconnected to the server.", ServerLog.MessageType.Connection);
                        GameServer.LogToClientconsole(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") has reconnected to the server.");
                    }
                }
            }
        }
예제 #3
0
        private void ReadConnectionInitializationStep(PendingClient pendingClient, NetIncomingMessage inc)
        {
            if (netServer == null)
            {
                return;
            }

            pendingClient.TimeOut = NetworkConnection.TimeoutThreshold;

            ConnectionInitialization initializationStep = (ConnectionInitialization)inc.ReadByte();

            //DebugConsole.NewMessage(initializationStep+" "+pendingClient.InitializationStep);

            if (pendingClient.InitializationStep != initializationStep)
            {
                return;
            }

            pendingClient.UpdateTime = Timing.TotalTime + Timing.Step;

            switch (initializationStep)
            {
            case ConnectionInitialization.SteamTicketAndVersion:
                string name         = Client.SanitizeName(inc.ReadString());
                int    ownKey       = inc.ReadInt32();
                UInt64 steamId      = inc.ReadUInt64();
                UInt16 ticketLength = inc.ReadUInt16();
                byte[] ticket       = inc.ReadBytes(ticketLength);

                if (!Client.IsValidName(name, serverSettings))
                {
                    if (OwnerConnection != null ||
                        !IPAddress.IsLoopback(pendingClient.Connection.RemoteEndPoint.Address.MapToIPv4NoThrow()) &&
                        ownerKey == null || ownKey == 0 && ownKey != ownerKey)
                    {
                        RemovePendingClient(pendingClient, DisconnectReason.InvalidName, "The name \"" + name + "\" is invalid");
                        return;
                    }
                }

                string version             = inc.ReadString();
                bool   isCompatibleVersion = NetworkMember.IsCompatible(version, GameMain.Version.ToString()) ?? false;
                if (!isCompatibleVersion)
                {
                    RemovePendingClient(pendingClient, DisconnectReason.InvalidVersion,
                                        $"DisconnectMessage.InvalidVersion~[version]={GameMain.Version}~[clientversion]={version}");

                    GameServer.Log(name + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (incompatible game version)", ServerLog.MessageType.Error);
                    DebugConsole.NewMessage(name + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (incompatible game version)", Microsoft.Xna.Framework.Color.Red);
                    return;
                }

                Client nameTaken = GameMain.Server.ConnectedClients.Find(c => Homoglyphs.Compare(c.Name.ToLower(), name.ToLower()));
                if (nameTaken != null)
                {
                    RemovePendingClient(pendingClient, DisconnectReason.NameTaken, "");
                    GameServer.Log(name + " (" + inc.SenderConnection.RemoteEndPoint.Address + ") couldn't join the server (name too similar to the name of the client \"" + nameTaken.Name + "\").", ServerLog.MessageType.Error);
                    return;
                }

                int contentPackageCount = inc.ReadVariableInt32();
                List <ClientContentPackage> clientContentPackages = new List <ClientContentPackage>();
                for (int i = 0; i < contentPackageCount; i++)
                {
                    string packageName = inc.ReadString();
                    string packageHash = inc.ReadString();
                    clientContentPackages.Add(new ClientContentPackage(packageName, packageHash));
                }

                //check if the client is missing any of our packages
                List <ContentPackage> missingPackages = new List <ContentPackage>();
                foreach (ContentPackage serverContentPackage in GameMain.SelectedPackages)
                {
                    if (!serverContentPackage.HasMultiplayerIncompatibleContent)
                    {
                        continue;
                    }
                    bool packageFound = clientContentPackages.Any(cp => cp.Name == serverContentPackage.Name && cp.Hash == serverContentPackage.MD5hash.Hash);
                    if (!packageFound)
                    {
                        missingPackages.Add(serverContentPackage);
                    }
                }

                //check if the client is using packages we don't have
                List <ClientContentPackage> redundantPackages = new List <ClientContentPackage>();
                foreach (ClientContentPackage clientContentPackage in clientContentPackages)
                {
                    bool packageFound = GameMain.SelectedPackages.Any(cp => cp.Name == clientContentPackage.Name && cp.MD5hash.Hash == clientContentPackage.Hash);
                    if (!packageFound)
                    {
                        redundantPackages.Add(clientContentPackage);
                    }
                }

                if (missingPackages.Count == 1)
                {
                    RemovePendingClient(pendingClient, DisconnectReason.MissingContentPackage,
                                        $"DisconnectMessage.MissingContentPackage~[missingcontentpackage]={GetPackageStr(missingPackages[0])}");
                    GameServer.Log(name + " (" + inc.SenderConnection.RemoteEndPoint.Address + ") couldn't join the server (missing content package " + GetPackageStr(missingPackages[0]) + ")", ServerLog.MessageType.Error);
                    return;
                }
                else if (missingPackages.Count > 1)
                {
                    List <string> packageStrs = new List <string>();
                    missingPackages.ForEach(cp => packageStrs.Add(GetPackageStr(cp)));
                    RemovePendingClient(pendingClient, DisconnectReason.MissingContentPackage,
                                        $"DisconnectMessage.MissingContentPackages~[missingcontentpackages]={string.Join(", ", packageStrs)}");
                    GameServer.Log(name + " (" + inc.SenderConnection.RemoteEndPoint.Address + ") couldn't join the server (missing content packages " + string.Join(", ", packageStrs) + ")", ServerLog.MessageType.Error);
                    return;
                }
                if (redundantPackages.Count == 1)
                {
                    RemovePendingClient(pendingClient, DisconnectReason.IncompatibleContentPackage,
                                        $"DisconnectMessage.IncompatibleContentPackage~[incompatiblecontentpackage]={GetPackageStr(redundantPackages[0])}");
                    GameServer.Log(name + " (" + inc.SenderConnection.RemoteEndPoint.Address + ") couldn't join the server (using an incompatible content package " + GetPackageStr(redundantPackages[0]) + ")", ServerLog.MessageType.Error);
                    return;
                }
                if (redundantPackages.Count > 1)
                {
                    List <string> packageStrs = new List <string>();
                    redundantPackages.ForEach(cp => packageStrs.Add(GetPackageStr(cp)));
                    RemovePendingClient(pendingClient, DisconnectReason.IncompatibleContentPackage,
                                        $"DisconnectMessage.IncompatibleContentPackages~[incompatiblecontentpackages]={string.Join(", ", packageStrs)}");
                    GameServer.Log(name + " (" + inc.SenderConnection.RemoteEndPoint.Address + ") couldn't join the server (using incompatible content packages " + string.Join(", ", packageStrs) + ")", ServerLog.MessageType.Error);
                    return;
                }

                if (pendingClient.SteamID == null)
                {
                    bool requireSteamAuth = GameMain.Config.RequireSteamAuthentication;
#if DEBUG
                    requireSteamAuth = false;
#endif
                        << << << < HEAD
                        pendingClient.Name           = name;
                    pendingClient.OwnerKey           = ownKey;
                    pendingClient.InitializationStep = serverSettings.HasPassword ? ConnectionInitialization.Password : ConnectionInitialization.ContentPackageOrder;
예제 #4
0
        private void ReadConnectionInitializationStep(PendingClient pendingClient, IReadMessage inc)
        {
            if (!started)
            {
                return;
            }

            pendingClient.TimeOut = NetworkConnection.TimeoutThreshold;

            ConnectionInitialization initializationStep = (ConnectionInitialization)inc.ReadByte();

            //DebugConsole.NewMessage(initializationStep+" "+pendingClient.InitializationStep);

            if (pendingClient.InitializationStep != initializationStep)
            {
                return;
            }

            pendingClient.UpdateTime = Timing.TotalTime + Timing.Step;

            switch (initializationStep)
            {
            case ConnectionInitialization.SteamTicketAndVersion:
                string name         = Client.SanitizeName(inc.ReadString());
                UInt64 steamId      = inc.ReadUInt64();
                UInt16 ticketLength = inc.ReadUInt16();
                inc.BitPosition += ticketLength * 8;     //skip ticket, owner handles steam authentication

                if (!Client.IsValidName(name, serverSettings))
                {
                    RemovePendingClient(pendingClient, DisconnectReason.InvalidName, "The name \"" + name + "\" is invalid");
                    return;
                }

                string version             = inc.ReadString();
                bool   isCompatibleVersion = NetworkMember.IsCompatible(version, GameMain.Version.ToString()) ?? false;
                if (!isCompatibleVersion)
                {
                    RemovePendingClient(pendingClient, DisconnectReason.InvalidVersion,
                                        $"DisconnectMessage.InvalidVersion~[version]={GameMain.Version}~[clientversion]={version}");

                    GameServer.Log(name + " (" + pendingClient.SteamID.ToString() + ") couldn't join the server (incompatible game version)", ServerLog.MessageType.Error);
                    DebugConsole.NewMessage(name + " (" + pendingClient.SteamID.ToString() + ") couldn't join the server (incompatible game version)", Microsoft.Xna.Framework.Color.Red);
                    return;
                }

                Client nameTaken = GameMain.Server.ConnectedClients.Find(c => Homoglyphs.Compare(c.Name.ToLower(), name.ToLower()));
                if (nameTaken != null)
                {
                    RemovePendingClient(pendingClient, DisconnectReason.NameTaken, "");
                    GameServer.Log(name + " (" + pendingClient.SteamID.ToString() + ") couldn't join the server (name too similar to the name of the client \"" + nameTaken.Name + "\").", ServerLog.MessageType.Error);
                    return;
                }

                int contentPackageCount = (int)inc.ReadVariableUInt32();
                List <ClientContentPackage> clientContentPackages = new List <ClientContentPackage>();
                for (int i = 0; i < contentPackageCount; i++)
                {
                    string packageName = inc.ReadString();
                    string packageHash = inc.ReadString();
                    clientContentPackages.Add(new ClientContentPackage(packageName, packageHash));
                }

                //check if the client is missing any of our packages
                List <ContentPackage> missingPackages = new List <ContentPackage>();
                foreach (ContentPackage serverContentPackage in GameMain.SelectedPackages)
                {
                    if (!serverContentPackage.HasMultiplayerIncompatibleContent)
                    {
                        continue;
                    }
                    bool packageFound = clientContentPackages.Any(cp => cp.Name == serverContentPackage.Name && cp.Hash == serverContentPackage.MD5hash.Hash);
                    if (!packageFound)
                    {
                        missingPackages.Add(serverContentPackage);
                    }
                }

                //check if the client is using packages we don't have
                List <ClientContentPackage> redundantPackages = new List <ClientContentPackage>();
                foreach (ClientContentPackage clientContentPackage in clientContentPackages)
                {
                    bool packageFound = GameMain.SelectedPackages.Any(cp => cp.Name == clientContentPackage.Name && cp.MD5hash.Hash == clientContentPackage.Hash);
                    if (!packageFound)
                    {
                        redundantPackages.Add(clientContentPackage);
                    }
                }

                if (missingPackages.Count == 1)
                {
                    RemovePendingClient(pendingClient, DisconnectReason.MissingContentPackage,
                                        $"DisconnectMessage.MissingContentPackage~[missingcontentpackage]={GetPackageStr(missingPackages[0])}");
                    GameServer.Log(name + " (" + pendingClient.SteamID + ") couldn't join the server (missing content package " + GetPackageStr(missingPackages[0]) + ")", ServerLog.MessageType.Error);
                    return;
                }
                else if (missingPackages.Count > 1)
                {
                    List <string> packageStrs = new List <string>();
                    missingPackages.ForEach(cp => packageStrs.Add(GetPackageStr(cp)));
                    RemovePendingClient(pendingClient, DisconnectReason.MissingContentPackage,
                                        $"DisconnectMessage.MissingContentPackages~[missingcontentpackages]={string.Join(", ", packageStrs)}");
                    GameServer.Log(name + " (" + pendingClient.SteamID + ") couldn't join the server (missing content packages " + string.Join(", ", packageStrs) + ")", ServerLog.MessageType.Error);
                    return;
                }
                if (redundantPackages.Count == 1)
                {
                    RemovePendingClient(pendingClient, DisconnectReason.IncompatibleContentPackage,
                                        $"DisconnectMessage.IncompatibleContentPackage~[incompatiblecontentpackage]={GetPackageStr(redundantPackages[0])}");
                    GameServer.Log(name + " (" + pendingClient.SteamID + ") couldn't join the server (using an incompatible content package " + GetPackageStr(redundantPackages[0]) + ")", ServerLog.MessageType.Error);
                    return;
                }
                if (redundantPackages.Count > 1)
                {
                    List <string> packageStrs = new List <string>();
                    redundantPackages.ForEach(cp => packageStrs.Add(GetPackageStr(cp)));
                    RemovePendingClient(pendingClient, DisconnectReason.IncompatibleContentPackage,
                                        $"DisconnectMessage.IncompatibleContentPackages~[incompatiblecontentpackages]={string.Join(", ", packageStrs)}");
                    GameServer.Log(name + " (" + pendingClient.SteamID + ") couldn't join the server (using incompatible content packages " + string.Join(", ", packageStrs) + ")", ServerLog.MessageType.Error);
                    return;
                }

                if (!pendingClient.AuthSessionStarted)
                {
                    pendingClient.InitializationStep = serverSettings.HasPassword ? ConnectionInitialization.Password : ConnectionInitialization.ContentPackageOrder;

                    pendingClient.Name = name;
                    pendingClient.AuthSessionStarted = true;
                }
                break;

            case ConnectionInitialization.Password:
                int    pwLength    = inc.ReadByte();
                byte[] incPassword = inc.ReadBytes(pwLength);
                if (pendingClient.PasswordSalt == null)
                {
                    DebugConsole.ThrowError("Received password message from client without salt");
                    return;
                }
                if (serverSettings.IsPasswordCorrect(incPassword, pendingClient.PasswordSalt.Value))
                {
                    pendingClient.InitializationStep = ConnectionInitialization.ContentPackageOrder;
                }
                else
                {
                    pendingClient.Retries++;
                    if (serverSettings.BanAfterWrongPassword && pendingClient.Retries > serverSettings.MaxPasswordRetriesBeforeBan)
                    {
                        string banMsg = "Failed to enter correct password too many times";
                        serverSettings.BanList.BanPlayer(pendingClient.Name, pendingClient.SteamID, banMsg, null);

                        RemovePendingClient(pendingClient, DisconnectReason.Banned, banMsg);
                        return;
                    }
                }
                pendingClient.UpdateTime = Timing.TotalTime;
                break;

            case ConnectionInitialization.ContentPackageOrder:
                pendingClient.InitializationStep = ConnectionInitialization.Success;
                pendingClient.UpdateTime         = Timing.TotalTime;
                break;
            }
        }
예제 #5
0
        private void ClientInitRequest(NetIncomingMessage inc)
        {
            DebugConsole.Log("Received client init request");
            if (ConnectedClients.Find(c => c.Connection == inc.SenderConnection) != null)
            {
                //this client was already authenticated
                //another init request means they didn't get any update packets yet
                DebugConsole.Log("Client already connected, ignoring...");
                return;
            }

            UnauthenticatedClient unauthClient = unauthenticatedClients.Find(uc => uc.Connection == inc.SenderConnection);

            if (unauthClient == null)
            {
                //client did not ask for nonce first, can't authorize
                inc.SenderConnection.Disconnect(DisconnectReason.AuthenticationRequired.ToString());
                if (unauthClient.SteamID > 0)
                {
                    Steam.SteamManager.StopAuthSession(unauthClient.SteamID);
                }
                return;
            }

            if (serverSettings.HasPassword && inc.SenderConnection != OwnerConnection)
            {
                //decrypt message and compare password
                string clPw = inc.ReadString();
                if (!serverSettings.IsPasswordCorrect(clPw, unauthClient.Nonce))
                {
                    unauthClient.FailedAttempts++;
                    if (unauthClient.FailedAttempts > 3)
                    {
                        //disconnect and ban after too many failed attempts
                        serverSettings.BanList.BanPlayer("Unnamed", unauthClient.Connection.RemoteEndPoint.Address, "DisconnectMessage.TooManyFailedLogins", duration: null);
                        DisconnectUnauthClient(inc, unauthClient, DisconnectReason.TooManyFailedLogins, "");

                        Log(inc.SenderConnection.RemoteEndPoint.Address.ToString() + " has been banned from the server (too many wrong passwords)", ServerLog.MessageType.Error);
                        DebugConsole.NewMessage(inc.SenderConnection.RemoteEndPoint.Address.ToString() + " has been banned from the server (too many wrong passwords)", Color.Red);
                        return;
                    }
                    else
                    {
                        //not disconnecting the player here, because they'll still use the same connection and nonce if they try logging in again
                        NetOutgoingMessage reject = server.CreateMessage();
                        reject.Write((byte)ServerPacketHeader.AUTH_FAILURE);
                        reject.Write("Wrong password! You have " + Convert.ToString(4 - unauthClient.FailedAttempts) + " more attempts before you're banned from the server.");
                        Log(inc.SenderConnection.RemoteEndPoint.Address.ToString() + " failed to join the server (incorrect password)", ServerLog.MessageType.Error);
                        DebugConsole.NewMessage(inc.SenderConnection.RemoteEndPoint.Address.ToString() + " failed to join the server (incorrect password)", Color.Red);
                        CompressOutgoingMessage(reject);
                        server.SendMessage(reject, unauthClient.Connection, NetDeliveryMethod.Unreliable);
                        unauthClient.AuthTimer = 10.0f;
                        return;
                    }
                }
            }
            string clVersion = inc.ReadString();

            UInt16        contentPackageCount  = inc.ReadUInt16();
            List <string> contentPackageNames  = new List <string>();
            List <string> contentPackageHashes = new List <string>();

            for (int i = 0; i < contentPackageCount; i++)
            {
                string packageName = inc.ReadString();
                string packageHash = inc.ReadString();
                contentPackageNames.Add(packageName);
                contentPackageHashes.Add(packageHash);
                if (contentPackageCount == 0)
                {
                    DebugConsole.Log("Client is using content package " +
                                     (packageName ?? "null") + " (" + (packageHash ?? "null" + ")"));
                }
            }

            if (contentPackageCount == 0)
            {
                DebugConsole.Log("Client did not list any content packages.");
            }

            string clName = Client.SanitizeName(inc.ReadString());

            if (string.IsNullOrWhiteSpace(clName))
            {
                DisconnectUnauthClient(inc, unauthClient, DisconnectReason.NoName, "");

                Log(inc.SenderConnection.RemoteEndPoint.Address.ToString() + " couldn't join the server (no name given)", ServerLog.MessageType.Error);
                DebugConsole.NewMessage(inc.SenderConnection.RemoteEndPoint.Address.ToString() + " couldn't join the server (no name given)", Color.Red);
                return;
            }

            if (clVersion != GameMain.Version.ToString())
            {
                DisconnectUnauthClient(inc, unauthClient, DisconnectReason.InvalidVersion,
                                       $"DisconnectMessage.InvalidVersion~[version]={GameMain.Version.ToString()}~[clientversion]={clVersion}");

                Log(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (wrong game version)", ServerLog.MessageType.Error);
                DebugConsole.NewMessage(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (wrong game version)", Color.Red);
                return;
            }

            //check if the client is missing any of the content packages the server requires
            List <ContentPackage> missingPackages = new List <ContentPackage>();

            foreach (ContentPackage contentPackage in GameMain.SelectedPackages)
            {
                if (!contentPackage.HasMultiplayerIncompatibleContent)
                {
                    continue;
                }
                bool packageFound = false;
                for (int i = 0; i < contentPackageCount; i++)
                {
                    if (contentPackageNames[i] == contentPackage.Name && contentPackageHashes[i] == contentPackage.MD5hash.Hash)
                    {
                        packageFound = true;
                        break;
                    }
                }
                if (!packageFound)
                {
                    missingPackages.Add(contentPackage);
                }
            }

            if (missingPackages.Count == 1)
            {
                DisconnectUnauthClient(inc, unauthClient, DisconnectReason.MissingContentPackage, $"DisconnectMessage.MissingContentPackage~[missingcontentpackage]={GetPackageStr(missingPackages[0])}");
                Log(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (missing content package " + GetPackageStr(missingPackages[0]) + ")", ServerLog.MessageType.Error);
                return;
            }
            else if (missingPackages.Count > 1)
            {
                List <string> packageStrs = new List <string>();
                missingPackages.ForEach(cp => packageStrs.Add(GetPackageStr(cp)));
                DisconnectUnauthClient(inc, unauthClient, DisconnectReason.MissingContentPackage, $"DisconnectMessage.MissingContentPackages~[missingcontentpackages]={string.Join(", ", packageStrs)}");
                Log(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (missing content packages " + string.Join(", ", packageStrs) + ")", ServerLog.MessageType.Error);
                return;
            }

            string GetPackageStr(ContentPackage contentPackage)
            {
                return("\"" + contentPackage.Name + "\" (hash " + contentPackage.MD5hash.ShortHash + ")");
            }

            //check if the client is using any contentpackages that are not compatible with the server
            List <Pair <string, string> > incompatiblePackages = new List <Pair <string, string> >();

            for (int i = 0; i < contentPackageNames.Count; i++)
            {
                if (!GameMain.Config.SelectedContentPackages.Any(cp => cp.Name == contentPackageNames[i] && cp.MD5hash.Hash == contentPackageHashes[i]))
                {
                    incompatiblePackages.Add(new Pair <string, string>(contentPackageNames[i], contentPackageHashes[i]));
                }
            }

            if (incompatiblePackages.Count == 1)
            {
                DisconnectUnauthClient(inc, unauthClient, DisconnectReason.IncompatibleContentPackage,
                                       $"DisconnectMessage.IncompatibleContentPackage~[incompatiblecontentpackage]={GetPackageStr2(incompatiblePackages[0])}");
                Log(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (incompatible content package " + GetPackageStr2(incompatiblePackages[0]) + ")", ServerLog.MessageType.Error);
                return;
            }
            else if (incompatiblePackages.Count > 1)
            {
                List <string> packageStrs = new List <string>();
                incompatiblePackages.ForEach(cp => packageStrs.Add(GetPackageStr2(cp)));
                DisconnectUnauthClient(inc, unauthClient, DisconnectReason.IncompatibleContentPackage,
                                       $"DisconnectMessage.IncompatibleContentPackages~[incompatiblecontentpackages]={string.Join(", ", packageStrs)}");
                Log(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (incompatible content packages " + string.Join(", ", packageStrs) + ")", ServerLog.MessageType.Error);
                return;
            }

            string GetPackageStr2(Pair <string, string> nameAndHash)
            {
                return("\"" + nameAndHash.First + "\" (hash " + Md5Hash.GetShortHash(nameAndHash.Second) + ")");
            }

            if (!serverSettings.Whitelist.IsWhiteListed(clName, inc.SenderConnection.RemoteEndPoint.Address))
            {
                DisconnectUnauthClient(inc, unauthClient, DisconnectReason.NotOnWhitelist, "");
                Log(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (not in whitelist)", ServerLog.MessageType.Error);
                DebugConsole.NewMessage(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (not in whitelist)", Color.Red);
                return;
            }
            if (!Client.IsValidName(clName, this))
            {
                DisconnectUnauthClient(inc, unauthClient, DisconnectReason.InvalidName, "");
                Log(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (invalid name)", ServerLog.MessageType.Error);
                DebugConsole.NewMessage(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (invalid name)", Color.Red);
                return;
            }
            if (inc.SenderConnection != OwnerConnection && Homoglyphs.Compare(clName.ToLower(), Name.ToLower()))
            {
                DisconnectUnauthClient(inc, unauthClient, DisconnectReason.NameTaken, "");
                Log(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (name taken by the server)", ServerLog.MessageType.Error);
                DebugConsole.NewMessage(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (name taken by the server)", Color.Red);
                return;
            }
            Client nameTaken = ConnectedClients.Find(c => Homoglyphs.Compare(c.Name.ToLower(), clName.ToLower()));

            if (nameTaken != null)
            {
                if (nameTaken.Connection.RemoteEndPoint.Address.ToString() == inc.SenderEndPoint.Address.ToString())
                {
                    //both name and IP address match, replace this player's connection
                    nameTaken.Connection.Disconnect(DisconnectReason.SessionTaken.ToString());
                    nameTaken.Connection = unauthClient.Connection;
                    nameTaken.InitClientSync(); //reinitialize sync ids because this is a new connection
                    unauthenticatedClients.Remove(unauthClient);
                    unauthClient = null;
                    return;
                }
                else
                {
                    //can't authorize this client
                    DisconnectUnauthClient(inc, unauthClient, DisconnectReason.NameTaken, "");
                    Log(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (name already taken)", ServerLog.MessageType.Error);
                    DebugConsole.NewMessage(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (name already taken)", Color.Red);
                    return;
                }
            }

            //new client
            Client newClient = new Client(clName, GetNewClientID());

            newClient.InitClientSync();
            newClient.Connection = unauthClient.Connection;
            newClient.SteamID    = unauthClient.SteamID;
            unauthenticatedClients.Remove(unauthClient);
            unauthClient = null;
            ConnectedClients.Add(newClient);
            LastClientListUpdateID++;

            if (newClient.Connection == OwnerConnection)
            {
                newClient.GivePermission(ClientPermissions.All);
                newClient.PermittedConsoleCommands.AddRange(DebugConsole.Commands);

                GameMain.Server.UpdateClientPermissions(newClient);
                GameMain.Server.SendConsoleMessage("Granted all permissions to " + newClient.Name + ".", newClient);
            }

            GameMain.Server.SendChatMessage($"ServerMessage.JoinedServer~[client]={clName}", ChatMessageType.Server, null);

            var savedPermissions = serverSettings.ClientPermissions.Find(cp =>
                                                                         cp.SteamID > 0 ?
                                                                         cp.SteamID == newClient.SteamID :
                                                                         newClient.IPMatches(cp.IP));

            if (savedPermissions != null)
            {
                newClient.SetPermissions(savedPermissions.Permissions, savedPermissions.PermittedCommands);
            }
            else
            {
                newClient.SetPermissions(ClientPermissions.None, new List <DebugConsole.Command>());
            }
        }
        private void ClientInitRequest(NetIncomingMessage inc)
        {
            if (ConnectedClients.Find(c => c.Connection == inc.SenderConnection) != null)
            {
                //this client was already authenticated
                //another init request means they didn't get any update packets yet
                return;
            }

            UnauthenticatedClient unauthClient = unauthenticatedClients.Find(uc => uc.Connection == inc.SenderConnection);

            if (unauthClient == null)
            {
                //client did not ask for nonce first, can't authorize
                inc.SenderConnection.Disconnect("Client did not properly request authentication.");
                return;
            }

            if (!string.IsNullOrEmpty(password))
            {
                //decrypt message and compare password
                string saltedPw = password;
                saltedPw = saltedPw + Convert.ToString(unauthClient.Nonce);
                saltedPw = Encoding.UTF8.GetString(NetUtility.ComputeSHAHash(Encoding.UTF8.GetBytes(saltedPw)));
                string clPw = inc.ReadString();
                if (clPw != saltedPw)
                {
                    unauthClient.failedAttempts++;
                    if (unauthClient.failedAttempts > 3)
                    {
                        //disconnect and ban after too many failed attempts
                        banList.BanPlayer("Unnamed", unauthClient.Connection.RemoteEndPoint.Address.ToString(), "Too many failed login attempts.", null);
                        DisconnectUnauthClient(inc, unauthClient, "Too many failed login attempts. You have been automatically banned from the server.");

                        Log(inc.SenderConnection.RemoteEndPoint.Address.ToString() + " has been banned from the server (too many wrong passwords)", ServerLog.MessageType.Error);
                        DebugConsole.NewMessage(inc.SenderConnection.RemoteEndPoint.Address.ToString() + " has been banned from the server (too many wrong passwords)", Color.Red);
                        return;
                    }
                    else
                    {
                        //not disconnecting the player here, because they'll still use the same connection and nonce if they try logging in again
                        NetOutgoingMessage reject = server.CreateMessage();
                        reject.Write((byte)ServerPacketHeader.AUTH_FAILURE);
                        reject.Write("Wrong password! You have " + Convert.ToString(4 - unauthClient.failedAttempts) + " more attempts before you're banned from the server.");
                        Log(inc.SenderConnection.RemoteEndPoint.Address.ToString() + " failed to join the server (incorrect password)", ServerLog.MessageType.Error);
                        DebugConsole.NewMessage(inc.SenderConnection.RemoteEndPoint.Address.ToString() + " failed to join the server (incorrect password)", Color.Red);
                        server.SendMessage(reject, unauthClient.Connection, NetDeliveryMethod.Unreliable);
                        unauthClient.AuthTimer = 10.0f;
                        return;
                    }
                }
            }
            string clVersion     = inc.ReadString();
            string clPackageName = inc.ReadString();
            string clPackageHash = inc.ReadString();

            string clName = Client.SanitizeName(inc.ReadString());

            if (string.IsNullOrWhiteSpace(clName))
            {
                DisconnectUnauthClient(inc, unauthClient, "You need a name.");

                Log(inc.SenderConnection.RemoteEndPoint.Address.ToString() + " couldn't join the server (no name given)", ServerLog.MessageType.Error);
                DebugConsole.NewMessage(inc.SenderConnection.RemoteEndPoint.Address.ToString() + " couldn't join the server (no name given)", Color.Red);
                return;
            }

            if (clVersion != GameMain.Version.ToString())
            {
                DisconnectUnauthClient(inc, unauthClient, "Version " + GameMain.Version + " required to connect to the server (Your version: " + clVersion + ")");

                Log(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (wrong game version)", ServerLog.MessageType.Error);
                DebugConsole.NewMessage(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (wrong game version)", Color.Red);
                return;
            }
            if (clPackageName != GameMain.SelectedPackage.Name)
            {
                DisconnectUnauthClient(inc, unauthClient, "Your content package (" + clPackageName + ") doesn't match the server's version (" + GameMain.SelectedPackage.Name + ")");
                Log(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (wrong content package name)", ServerLog.MessageType.Error);
                DebugConsole.NewMessage(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (wrong content package name)", Color.Red);
                return;
            }
            if (clPackageHash != GameMain.SelectedPackage.MD5hash.Hash)
            {
                DisconnectUnauthClient(inc, unauthClient, "Your content package (MD5: " + clPackageHash + ") doesn't match the server's version (MD5: " + GameMain.SelectedPackage.MD5hash.Hash + ")");
                Log(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (wrong content package hash)", ServerLog.MessageType.Error);
                DebugConsole.NewMessage(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (wrong content package hash)", Color.Red);
                return;
            }

            if (!whitelist.IsWhiteListed(clName, inc.SenderConnection.RemoteEndPoint.Address.ToString()))
            {
                DisconnectUnauthClient(inc, unauthClient, "You're not in this server's whitelist.");
                Log(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (not in whitelist)", ServerLog.MessageType.Error);
                DebugConsole.NewMessage(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (not in whitelist)", Color.Red);
                return;
            }
            if (!Client.IsValidName(clName))
            {
                DisconnectUnauthClient(inc, unauthClient, "Your name contains illegal symbols.");
                Log(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (invalid name)", ServerLog.MessageType.Error);
                DebugConsole.NewMessage(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (invalid name)", Color.Red);
                return;
            }
            if (Homoglyphs.Compare(clName.ToLower(), Name.ToLower()))
            {
                DisconnectUnauthClient(inc, unauthClient, "That name is taken.");
                Log(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (name taken by the server)", ServerLog.MessageType.Error);
                DebugConsole.NewMessage(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (name taken by the server)", Color.Red);
                return;
            }
            Client nameTaken = ConnectedClients.Find(c => Homoglyphs.Compare(c.Name.ToLower(), clName.ToLower()));

            if (nameTaken != null)
            {
                if (nameTaken.Connection.RemoteEndPoint.Address.ToString() == inc.SenderEndPoint.Address.ToString())
                {
                    //both name and IP address match, replace this player's connection
                    nameTaken.Connection.Disconnect("Your session was taken by a new connection on the same IP address.");
                    nameTaken.Connection = unauthClient.Connection;
                    nameTaken.InitClientSync(); //reinitialize sync ids because this is a new connection
                    unauthenticatedClients.Remove(unauthClient);
                    unauthClient = null;
                    return;
                }
                else
                {
                    //can't authorize this client
                    DisconnectUnauthClient(inc, unauthClient, "That name is taken.");
                    Log(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (name already taken)", ServerLog.MessageType.Error);
                    DebugConsole.NewMessage(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (name already taken)", Color.Red);
                    return;
                }
            }

            //new client
            Client newClient = new Client(clName, GetNewClientID());

            newClient.InitClientSync();
            newClient.Connection = unauthClient.Connection;
            unauthenticatedClients.Remove(unauthClient);
            unauthClient = null;
            ConnectedClients.Add(newClient);

#if CLIENT
            GameMain.NetLobbyScreen.AddPlayer(newClient.Name);
#endif
            GameMain.Server.SendChatMessage(clName + " has joined the server.", ChatMessageType.Server, null);

            var savedPermissions = clientPermissions.Find(cp => cp.IP == newClient.Connection.RemoteEndPoint.Address.ToString());
            if (savedPermissions != null)
            {
                newClient.SetPermissions(savedPermissions.Permissions, savedPermissions.PermittedCommands);
            }
            else
            {
                newClient.SetPermissions(ClientPermissions.None, new List <DebugConsole.Command>());
            }
        }
예제 #7
0
        protected void ReadConnectionInitializationStep(PendingClient pendingClient, IReadMessage inc)
        {
            pendingClient.TimeOut = NetworkConnection.TimeoutThreshold;

            ConnectionInitialization initializationStep = (ConnectionInitialization)inc.ReadByte();

            if (pendingClient.InitializationStep != initializationStep)
            {
                return;
            }

            pendingClient.UpdateTime = Timing.TotalTime + Timing.Step;

            switch (initializationStep)
            {
            case ConnectionInitialization.SteamTicketAndVersion:
                string name         = Client.SanitizeName(inc.ReadString());
                int    ownerKey     = inc.ReadInt32();
                UInt64 steamId      = inc.ReadUInt64();
                UInt16 ticketLength = inc.ReadUInt16();
                byte[] ticketBytes  = inc.ReadBytes(ticketLength);

                if (!Client.IsValidName(name, serverSettings))
                {
                    RemovePendingClient(pendingClient, DisconnectReason.InvalidName, "");
                    return;
                }

                string version             = inc.ReadString();
                bool   isCompatibleVersion = NetworkMember.IsCompatible(version, GameMain.Version.ToString()) ?? false;
                if (!isCompatibleVersion)
                {
                    RemovePendingClient(pendingClient, DisconnectReason.InvalidVersion,
                                        $"DisconnectMessage.InvalidVersion~[version]={GameMain.Version}~[clientversion]={version}");

                    GameServer.Log(name + " (" + pendingClient.SteamID.ToString() + ") couldn't join the server (incompatible game version)", ServerLog.MessageType.Error);
                    DebugConsole.NewMessage(name + " (" + pendingClient.SteamID.ToString() + ") couldn't join the server (incompatible game version)", Microsoft.Xna.Framework.Color.Red);
                    return;
                }

                string language = inc.ReadString();
                pendingClient.Connection.Language = language;

                Client nameTaken = GameMain.Server.ConnectedClients.Find(c => Homoglyphs.Compare(c.Name.ToLower(), name.ToLower()));
                if (nameTaken != null)
                {
                    RemovePendingClient(pendingClient, DisconnectReason.NameTaken, "");
                    GameServer.Log(name + " (" + pendingClient.SteamID.ToString() + ") couldn't join the server (name too similar to the name of the client \"" + nameTaken.Name + "\").", ServerLog.MessageType.Error);
                    return;
                }

                if (!pendingClient.AuthSessionStarted)
                {
                    ProcessAuthTicket(name, ownerKey, steamId, pendingClient, ticketBytes);
                }
                break;

            case ConnectionInitialization.Password:
                int    pwLength    = inc.ReadByte();
                byte[] incPassword = inc.ReadBytes(pwLength);
                if (pendingClient.PasswordSalt == null)
                {
                    DebugConsole.ThrowError("Received password message from client without salt");
                    return;
                }
                if (serverSettings.IsPasswordCorrect(incPassword, pendingClient.PasswordSalt.Value))
                {
                    pendingClient.InitializationStep = ConnectionInitialization.ContentPackageOrder;
                }
                else
                {
                    pendingClient.Retries++;
                    if (serverSettings.BanAfterWrongPassword && pendingClient.Retries > serverSettings.MaxPasswordRetriesBeforeBan)
                    {
                        string banMsg = "Failed to enter correct password too many times";
                        BanPendingClient(pendingClient, banMsg, null);

                        RemovePendingClient(pendingClient, DisconnectReason.Banned, banMsg);
                        return;
                    }
                }
                pendingClient.UpdateTime = Timing.TotalTime;
                break;

            case ConnectionInitialization.ContentPackageOrder:
                pendingClient.InitializationStep = ConnectionInitialization.Success;
                pendingClient.UpdateTime         = Timing.TotalTime;
                break;
            }
        }
예제 #8
0
        private void ReadConnectionInitializationStep(PendingClient pendingClient, NetIncomingMessage inc)
        {
            if (netServer == null)
            {
                return;
            }

            pendingClient.TimeOut = NetworkConnection.TimeoutThreshold;

            ConnectionInitialization initializationStep = (ConnectionInitialization)inc.ReadByte();

            //DebugConsole.NewMessage(initializationStep+" "+pendingClient.InitializationStep);

            if (pendingClient.InitializationStep != initializationStep)
            {
                return;
            }

            pendingClient.UpdateTime = Timing.TotalTime + Timing.Step;

            switch (initializationStep)
            {
            case ConnectionInitialization.SteamTicketAndVersion:
                string name         = Client.SanitizeName(inc.ReadString());
                int    ownKey       = inc.ReadInt32();
                UInt64 steamId      = inc.ReadUInt64();
                UInt16 ticketLength = inc.ReadUInt16();
                byte[] ticket       = inc.ReadBytes(ticketLength);

                if (!Client.IsValidName(name, serverSettings))
                {
                    if (OwnerConnection != null ||
                        !IPAddress.IsLoopback(pendingClient.Connection.RemoteEndPoint.Address.MapToIPv4NoThrow()) &&
                        ownerKey == null || ownKey == 0 && ownKey != ownerKey)
                    {
                        RemovePendingClient(pendingClient, DisconnectReason.InvalidName, "The name \"" + name + "\" is invalid");
                        return;
                    }
                }

                string version             = inc.ReadString();
                bool   isCompatibleVersion = NetworkMember.IsCompatible(version, GameMain.Version.ToString()) ?? false;
                if (!isCompatibleVersion)
                {
                    RemovePendingClient(pendingClient, DisconnectReason.InvalidVersion,
                                        $"DisconnectMessage.InvalidVersion~[version]={GameMain.Version}~[clientversion]={version}");

                    GameServer.Log(name + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (incompatible game version)", ServerLog.MessageType.Error);
                    DebugConsole.NewMessage(name + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (incompatible game version)", Microsoft.Xna.Framework.Color.Red);
                    return;
                }

                Client nameTaken = GameMain.Server.ConnectedClients.Find(c => Homoglyphs.Compare(c.Name.ToLower(), name.ToLower()));
                if (nameTaken != null)
                {
                    RemovePendingClient(pendingClient, DisconnectReason.NameTaken, "");
                    GameServer.Log(name + " (" + inc.SenderConnection.RemoteEndPoint.Address + ") couldn't join the server (name too similar to the name of the client \"" + nameTaken.Name + "\").", ServerLog.MessageType.Error);
                    return;
                }

                int contentPackageCount = inc.ReadVariableInt32();
                List <ClientContentPackage> clientContentPackages = new List <ClientContentPackage>();
                for (int i = 0; i < contentPackageCount; i++)
                {
                    string packageName = inc.ReadString();
                    string packageHash = inc.ReadString();
                    clientContentPackages.Add(new ClientContentPackage(packageName, packageHash));
                }

                //check if the client is missing any of our packages
                List <ContentPackage> missingPackages = new List <ContentPackage>();
                foreach (ContentPackage serverContentPackage in GameMain.SelectedPackages)
                {
                    if (!serverContentPackage.HasMultiplayerIncompatibleContent)
                    {
                        continue;
                    }
                    bool packageFound = clientContentPackages.Any(cp => cp.Name == serverContentPackage.Name && cp.Hash == serverContentPackage.MD5hash.Hash);
                    if (!packageFound)
                    {
                        missingPackages.Add(serverContentPackage);
                    }
                }

                //check if the client is using packages we don't have
                List <ClientContentPackage> redundantPackages = new List <ClientContentPackage>();
                foreach (ClientContentPackage clientContentPackage in clientContentPackages)
                {
                    bool packageFound = GameMain.SelectedPackages.Any(cp => cp.Name == clientContentPackage.Name && cp.MD5hash.Hash == clientContentPackage.Hash);
                    if (!packageFound)
                    {
                        redundantPackages.Add(clientContentPackage);
                    }
                }

                if (missingPackages.Count == 1)
                {
                    RemovePendingClient(pendingClient, DisconnectReason.MissingContentPackage,
                                        $"DisconnectMessage.MissingContentPackage~[missingcontentpackage]={GetPackageStr(missingPackages[0])}");
                    GameServer.Log(name + " (" + inc.SenderConnection.RemoteEndPoint.Address + ") couldn't join the server (missing content package " + GetPackageStr(missingPackages[0]) + ")", ServerLog.MessageType.Error);
                    return;
                }
                else if (missingPackages.Count > 1)
                {
                    List <string> packageStrs = new List <string>();
                    missingPackages.ForEach(cp => packageStrs.Add(GetPackageStr(cp)));
                    RemovePendingClient(pendingClient, DisconnectReason.MissingContentPackage,
                                        $"DisconnectMessage.MissingContentPackages~[missingcontentpackages]={string.Join(", ", packageStrs)}");
                    GameServer.Log(name + " (" + inc.SenderConnection.RemoteEndPoint.Address + ") couldn't join the server (missing content packages " + string.Join(", ", packageStrs) + ")", ServerLog.MessageType.Error);
                    return;
                }
                if (redundantPackages.Count == 1)
                {
                    RemovePendingClient(pendingClient, DisconnectReason.IncompatibleContentPackage,
                                        $"DisconnectMessage.IncompatibleContentPackage~[incompatiblecontentpackage]={GetPackageStr(redundantPackages[0])}");
                    GameServer.Log(name + " (" + inc.SenderConnection.RemoteEndPoint.Address + ") couldn't join the server (using an incompatible content package " + GetPackageStr(redundantPackages[0]) + ")", ServerLog.MessageType.Error);
                    return;
                }
                if (redundantPackages.Count > 1)
                {
                    List <string> packageStrs = new List <string>();
                    redundantPackages.ForEach(cp => packageStrs.Add(GetPackageStr(cp)));
                    RemovePendingClient(pendingClient, DisconnectReason.IncompatibleContentPackage,
                                        $"DisconnectMessage.IncompatibleContentPackages~[incompatiblecontentpackages]={string.Join(", ", packageStrs)}");
                    GameServer.Log(name + " (" + inc.SenderConnection.RemoteEndPoint.Address + ") couldn't join the server (using incompatible content packages " + string.Join(", ", packageStrs) + ")", ServerLog.MessageType.Error);
                    return;
                }

                if (pendingClient.SteamID == null)
                {
                    bool requireSteamAuth = GameMain.Config.RequireSteamAuthentication;
#if DEBUG
                    requireSteamAuth = false;
#endif

                    //steam auth cannot be done (SteamManager not initialized or no ticket given),
                    //but it's not required either -> let the client join without auth
                    if ((!Steam.SteamManager.IsInitialized || (ticket?.Length ?? 0) == 0) &&
                        !requireSteamAuth)
                    {
                        pendingClient.Name               = name;
                        pendingClient.OwnerKey           = ownKey;
                        pendingClient.InitializationStep = serverSettings.HasPassword ? ConnectionInitialization.Password : ConnectionInitialization.ContentPackageOrder;
                    }
                    else
                    {
                        Steamworks.BeginAuthResult authSessionStartState = Steam.SteamManager.StartAuthSession(ticket, steamId);
                        if (authSessionStartState != Steamworks.BeginAuthResult.OK)
                        {
                            RemovePendingClient(pendingClient, DisconnectReason.SteamAuthenticationFailed, "Steam auth session failed to start: " + authSessionStartState.ToString());
                            return;
                        }
                        pendingClient.SteamID            = steamId;
                        pendingClient.Name               = name;
                        pendingClient.OwnerKey           = ownKey;
                        pendingClient.AuthSessionStarted = true;
                    }
                }
                else     //TODO: could remove since this seems impossible
                {
                    if (pendingClient.SteamID != steamId)
                    {
                        RemovePendingClient(pendingClient, DisconnectReason.SteamAuthenticationFailed, "SteamID mismatch");
                        return;
                    }
                }
                break;

            case ConnectionInitialization.Password:
                int    pwLength    = inc.ReadByte();
                byte[] incPassword = new byte[pwLength];
                inc.ReadBytes(incPassword, 0, pwLength);
                if (pendingClient.PasswordSalt == null)
                {
                    DebugConsole.ThrowError("Received password message from client without salt");
                    return;
                }
                if (serverSettings.IsPasswordCorrect(incPassword, pendingClient.PasswordSalt.Value))
                {
                    pendingClient.InitializationStep = ConnectionInitialization.ContentPackageOrder;
                }
                else
                {
                    pendingClient.Retries++;
                    if (serverSettings.BanAfterWrongPassword && pendingClient.Retries > serverSettings.MaxPasswordRetriesBeforeBan)
                    {
                        string banMsg = "Failed to enter correct password too many times";
                        if (pendingClient.SteamID != null)
                        {
                            serverSettings.BanList.BanPlayer(pendingClient.Name, pendingClient.SteamID.Value, banMsg, null);
                        }
                        serverSettings.BanList.BanPlayer(pendingClient.Name, pendingClient.Connection.RemoteEndPoint.Address, banMsg, null);
                        RemovePendingClient(pendingClient, DisconnectReason.Banned, banMsg);
                        return;
                    }
                }
                pendingClient.UpdateTime = Timing.TotalTime;
                break;

            case ConnectionInitialization.ContentPackageOrder:
                pendingClient.InitializationStep = ConnectionInitialization.Success;
                pendingClient.UpdateTime         = Timing.TotalTime;
                break;
            }
        }