public static IPBanInfo Load(string[] fields) { IPBanInfo info = new IPBanInfo(); if (fields == null) { throw new ArgumentNullException("fields"); } if (fields.Length != 8) { throw new ArgumentException("Unexpected field count", "fields"); } info.Address = IPAddress.Parse(fields[0]); info.BannedBy = PlayerInfo.Unescape(fields[1]); fields[2].ToDateTime(ref info.BanDate); if (fields[3].Length > 0) { info.BanReason = PlayerInfo.Unescape(fields[3]); } if (fields[4].Length > 0) { info.PlayerName = PlayerInfo.Unescape(fields[4]); } Int32.TryParse(fields[5], out info.Attempts); info.LastAttemptName = PlayerInfo.Unescape(fields[6]); fields[7].ToDateTime(ref info.LastAttemptDate); return(info); }
internal static IPBanInfo LoadFormat1([NotNull] string[] fields) { if (fields == null) { throw new ArgumentNullException("fields"); } if (fields.Length != 8) { throw new ArgumentException("Unexpected field count", "fields"); } IPBanInfo info = new IPBanInfo { Address = IPAddress.Parse(fields[0]), BannedBy = FlatfilePlayerDBProvider.Unescape(fields[1]) }; FlatfilePlayerDBProvider.ToDateTimeLegacy(fields[2], out info.BanDate); if (fields[3].Length > 0) { info.BanReason = FlatfilePlayerDBProvider.Unescape(fields[3]); } if (fields[4].Length > 0) { info.PlayerName = FlatfilePlayerDBProvider.Unescape(fields[4]); } Int32.TryParse(fields[5], out info.Attempts); info.LastAttemptName = FlatfilePlayerDBProvider.Unescape(fields[6]); FlatfilePlayerDBProvider.ToDateTimeLegacy(fields[7], out info.LastAttemptDate); return(info); }
static bool RaiseRemovingIPBanEvent([NotNull] IPBanInfo info) { var e = new IPBanCancelableEventArgs(info); RemovingIPBanEvent.Raise(e); return(!e.Cancel); }
/// <summary> Adds a new IP Ban. </summary> /// <param name="ban"> Ban information </param> /// <param name="raiseEvent"> Whether AddingIPBan and AddedIPBan events should be raised. </param> /// <returns> True if ban was added, false if it was already on the list </returns> public static bool Add([NotNull] IPBanInfo ban, bool raiseEvent) { if (ban == null) { throw new ArgumentNullException("ban"); } lock ( BanListLock ) { CheckIfLoaded(); if (Bans.ContainsKey(ban.Address.ToString())) { return(false); } if (raiseEvent) { if (RaiseAddingIPBanEvent(ban)) { return(false); } Bans.Add(ban.Address.ToString(), ban); RaiseAddedIPBanEvent(ban); } else { Bans.Add(ban.Address.ToString(), ban); } Save(); return(true); } }
internal static IPBanInfo LoadFormat2([NotNull] string[] fields) { if (fields == null) { throw new ArgumentNullException("fields"); } if (fields.Length != 8) { throw new ArgumentException("Unexpected field count", "fields"); } IPBanInfo info = new IPBanInfo { Address = IPAddress.Parse(fields[0]), BannedBy = PlayerDB.Unescape(fields[1]) }; DateTimeUtil.TryParseDateTime(fields[2], ref info.BanDate); if (fields[3].Length > 0) { info.BanReason = PlayerDB.Unescape(fields[3]); } if (fields[4].Length > 0) { info.PlayerName = PlayerDB.Unescape(fields[4]); } Int32.TryParse(fields[5], out info.Attempts); info.LastAttemptName = PlayerDB.Unescape(fields[6]); if (info.LastAttemptName.Length == 0) { info.LastAttemptName = null; } DateTimeUtil.TryParseDateTime(fields[7], ref info.LastAttemptDate); return(info); }
/// <summary> Removes a given IP address from the ban list (if present). </summary> /// <param name="address"> Address to unban. </param> /// <param name="raiseEvents"> Whether to raise RemovingIPBan and RemovedIPBan events. </param> /// <returns> True if IP was unbanned. /// False if it was not banned in the first place, or if it was cancelled by an event. </returns> public static bool Remove([NotNull] IPAddress address, bool raiseEvents) { if (address == null) { throw new ArgumentNullException("address"); } lock ( BanListLock ) { CheckIfLoaded(); if (!Bans.ContainsKey(address.ToString())) { return(false); } IPBanInfo info = Bans[address.ToString()]; if (raiseEvents) { if (RaiseRemovingIPBanEvent(info)) { return(false); } } if (Bans.Remove(address.ToString())) { if (raiseEvents) { RaiseRemovedIPBanEvent(info); } Save(); return(true); } else { return(false); } } }
internal void Load() { if (File.Exists(FileName)) { using (StreamReader reader = File.OpenText(FileName)) { reader.ReadLine(); // header while (!reader.EndOfStream) { string[] fields = reader.ReadLine().Split(','); if (fields.Length == IPBanInfo.fieldCount) { try { IPBanInfo ban = new IPBanInfo(fields); bans.Add(ban.address.ToString(), ban); } catch (FormatException ex) { world.log.Log("IPBanList.Load: Could not parse a record: {0}", LogType.Error, ex.Message); } catch (IOException ex) { world.log.Log("IPBanList.Load: Error while trying to read from file: {0}", LogType.Error, ex.Message); } } } } world.log.Log("IPBanList.Load: Done loading IP ban list ({0} records).", LogType.Debug, bans.Count); } else { world.log.Log("IPBanList.Load: No IP ban file found.", LogType.Warning); } }
static void RaiseRemovedIPBanEvent(IPBanInfo info) { var h = RemovedIPBan; if (h != null) { h(null, new IPBanEventArgs(info)); } }
public bool Add( IPBanInfo ban ) { lock( locker ) { if( !bans.ContainsKey( ban.address.ToString() ) ) { bans.Add( ban.address.ToString(), ban ); Save(); return true; } else { return false; } } }
static bool RaiseRemovingIPBanEvent(IPBanInfo info) { var h = RemovingIPBan; if (h == null) { return(false); } var e = new IPBanCancellableEventArgs(info); h(null, e); return(e.Cancel); }
static void RaiseRemovedIPBanEvent([NotNull] IPBanInfo info) { if (info == null) { throw new ArgumentNullException("info"); } var h = RemovedIPBan; if (h != null) { h(null, new IPBanEventArgs(info)); } }
public bool Add(IPBanInfo ban) { lock ( locker ) { if (!bans.ContainsKey(ban.address.ToString())) { bans.Add(ban.address.ToString(), ban); Save(); return(true); } else { return(false); } } }
static bool RaiseRemovingIPBanEvent([NotNull] IPBanInfo info) { if (info == null) { throw new ArgumentNullException("info"); } var h = RemovingIPBan; if (h == null) { return(false); } var e = new IPBanCancelableEventArgs(info); h(null, e); return(e.Cancel); }
internal static IPBanInfo LoadFormat0([NotNull] string[] fields, bool convertDatesToUtc) { if (fields == null) { throw new ArgumentNullException("fields"); } if (fields.Length != 8) { throw new ArgumentException("Unexpected field count", "fields"); } IPBanInfo info = new IPBanInfo { Address = IPAddress.Parse(fields[0]), BannedBy = PlayerDB.UnescapeOldFormat(fields[1]) }; DateTimeUtil.TryParseLocalDate(fields[2], out info.BanDate); info.BanReason = PlayerDB.UnescapeOldFormat(fields[3]); if (fields[4].Length > 1) { info.PlayerName = PlayerDB.UnescapeOldFormat(fields[4]); } info.Attempts = Int32.Parse(fields[5]); info.LastAttemptName = PlayerDB.UnescapeOldFormat(fields[6]); if (info.LastAttemptName.Length == 0) { info.LastAttemptName = null; } DateTimeUtil.TryParseLocalDate(fields[7], out info.LastAttemptDate); if (convertDatesToUtc) { if (info.BanDate != DateTime.MinValue) { info.BanDate = info.BanDate.ToUniversalTime(); } if (info.LastAttemptDate != DateTime.MinValue) { info.LastAttemptDate = info.LastAttemptDate.ToUniversalTime(); } } return(info); }
/// <summary> Adds a new IP Ban. </summary> /// <param name="ban"> Ban information </param> /// <returns> True if ban was added, false if it was already on the list </returns> public static bool Add(IPBanInfo ban) { if (ban == null) { throw new ArgumentNullException("ban"); } lock ( BanListLock ) { if (Bans.ContainsKey(ban.Address.ToString())) { return(false); } if (RaiseAddingIPBanEvent(ban)) { return(false); } Bans.Add(ban.Address.ToString(), ban); RaiseAddedIPBanEvent(ban); Save(); return(true); } }
internal static IPBanInfo LoadFormat1( [NotNull] string[] fields ) { if( fields == null ) throw new ArgumentNullException( "fields" ); if( fields.Length != 8 ) throw new ArgumentException( "Unexpected field count", "fields" ); IPBanInfo info = new IPBanInfo { Address = IPAddress.Parse( fields[0] ), BannedBy = PlayerInfo.Unescape( fields[1] ) }; fields[2].ToDateTimeLegacy( ref info.BanDate ); if( fields[3].Length > 0 ) { info.BanReason = PlayerInfo.Unescape( fields[3] ); } if( fields[4].Length > 0 ) { info.PlayerName = PlayerInfo.Unescape( fields[4] ); } Int32.TryParse( fields[5], out info.Attempts ); info.LastAttemptName = PlayerInfo.Unescape( fields[6] ); fields[7].ToDateTimeLegacy( ref info.LastAttemptDate ); return info; }
internal void Load() { if( File.Exists( FileName ) ) { using( StreamReader reader = File.OpenText( FileName ) ) { reader.ReadLine(); // header while( !reader.EndOfStream ) { string[] fields = reader.ReadLine().Split( ',' ); if( fields.Length == IPBanInfo.fieldCount ) { try { IPBanInfo ban = new IPBanInfo( fields ); bans.Add( ban.address.ToString(), ban ); } catch( FormatException ex ) { world.log.Log( "IPBanList.Load: Could not parse a record: {0}", LogType.Error, ex.Message ); } catch( IOException ex ) { world.log.Log( "IPBanList.Load: Error while trying to read from file: {0}", LogType.Error, ex.Message ); } } } } world.log.Log( "IPBanList.Load: Done loading IP ban list ({0} records).", LogType.Debug, bans.Count ); } else { world.log.Log( "IPBanList.Load: No IP ban file found.", LogType.Warning ); } }
/// <summary> Bans given IP address and all accounts on that IP. All players from IP are kicked. /// Throws PlayerOpException on problems. </summary> /// <param name="targetAddress"> IP address that is being banned. </param> /// <param name="player"> Player who is banning. </param> /// <param name="reason"> Reason for ban. May be empty, if permitted by server configuration. </param> /// <param name="announce"> Whether ban should be publicly announced on the server. </param> /// <param name="raiseEvents"> Whether AddingIPBan, AddedIPBan, BanChanging, and BanChanged events should be raised. </param> /// <exception cref="ArgumentNullException"> targetAddress or player is null. </exception> /// <exception cref="PlayerOpException"> Permission or configuration issues arise, or if everyone has already been banned. </exception> public static void BanAll([NotNull] this IPAddress targetAddress, [NotNull] Player player, [CanBeNull] string reason, bool announce, bool raiseEvents) { if (targetAddress == null) { throw new ArgumentNullException("targetAddress"); } if (player == null) { throw new ArgumentNullException("player"); } if (reason != null && reason.Trim().Length == 0) { reason = null; } if (!player.Can(Permission.Ban, Permission.BanIP, Permission.BanAll)) { PlayerOpException.ThrowPermissionMissing(player, null, "ban-all", Permission.Ban, Permission.BanIP, Permission.BanAll); } // Check if player is trying to ban self if (targetAddress.Equals(player.IP) && !player.IsSuper) { PlayerOpException.ThrowCannotTargetSelf(player, null, "ban-all"); } // Check if a non-bannable address was given (0.0.0.0 or 255.255.255.255) if (targetAddress.Equals(IPAddress.None) || targetAddress.Equals(IPAddress.Any)) { PlayerOpException.ThrowInvalidIP(player, null, targetAddress); } // Check if any high-ranked players use this address PlayerInfo[] allPlayersOnIP = PlayerDB.FindPlayers(targetAddress); PlayerInfo infoWhomPlayerCantBan = allPlayersOnIP.FirstOrDefault(info => !player.Can(Permission.Ban, info.Rank)); if (infoWhomPlayerCantBan != null) { PlayerOpException.ThrowPermissionLimitIP(player, infoWhomPlayerCantBan, targetAddress); } PlayerOpException.CheckBanReason(reason, player, null, false); bool somethingGotBanned = false; lock ( BanListLock ) { CheckIfLoaded(); // Ban the IP if (!Contains(targetAddress)) { IPBanInfo banInfo = new IPBanInfo(targetAddress, null, player.Name, reason); if (Add(banInfo, raiseEvents)) { Logger.Log(LogType.UserActivity, "{0} banned {1} (BanAll {1}). Reason: {2}", player.Name, targetAddress, reason ?? ""); // Announce ban on the server if (announce) { var can = Server.Players.Can(Permission.ViewPlayerIPs); can.Message("&W{0} was banned by {1}", targetAddress, player.ClassyName); var cant = Server.Players.Cant(Permission.ViewPlayerIPs); cant.Message("&WAn IP was banned by {0}", player.ClassyName); } somethingGotBanned = true; } } // Ban individual players foreach (PlayerInfo targetAlt in allPlayersOnIP) { if (targetAlt.BanStatus != BanStatus.NotBanned) { continue; } // Raise PlayerInfo.BanChanging event PlayerInfoBanChangingEventArgs e = new PlayerInfoBanChangingEventArgs(targetAlt, player, false, reason, announce); if (raiseEvents) { PlayerInfo.RaiseBanChangingEvent(e); if (e.Cancel) { continue; } reason = e.Reason; } // Do the ban if (targetAlt.ProcessBan(player, player.Name, reason)) { if (raiseEvents) { PlayerInfo.RaiseBanChangedEvent(e); } // Log and announce ban Logger.Log(LogType.UserActivity, "{0} banned {1} (BanAll {2}). Reason: {3}", player.Name, targetAlt.Name, targetAddress, reason ?? ""); if (announce) { Server.Message("&WPlayer {0}&W was banned by {1}&W (BanAll)", targetAlt.ClassyName, player.ClassyName); } somethingGotBanned = true; } } } // If no one ended up getting banned, quit here if (!somethingGotBanned) { PlayerOpException.ThrowNoOneToBan(player, null, targetAddress); } // Announce BanAll reason towards the end of all bans if (announce && ConfigKey.AnnounceKickAndBanReasons.Enabled() && reason != null) { Server.Message("&WBanAll reason: {0}", reason); } // Kick all players from IP Player[] targetsOnline = Server.Players.FromIP(targetAddress).ToArray(); if (targetsOnline.Length > 0) { string kickReason; if (reason != null) { kickReason = String.Format("Banned by {0}: {1}", player.Name, reason); } else { kickReason = String.Format("Banned by {0}", player.Name); } for (int i = 0; i < targetsOnline.Length; i++) { if (targetsOnline[i].Info.BanStatus != BanStatus.IPBanExempt) { targetsOnline[i].Kick(kickReason, LeaveReason.BanAll); } } } }
/// <summary> Bans given IP address. All players from IP are kicked. If an associated PlayerInfo is known, /// use a different overload of this method instead. Throws PlayerOpException on problems. </summary> /// <param name="targetAddress"> IP address that is being banned. </param> /// <param name="player"> Player who is banning. </param> /// <param name="reason"> Reason for ban. May be empty, if permitted by server configuration. </param> /// <param name="announce"> Whether ban should be publicly announced on the server. </param> /// <param name="raiseEvents"> Whether AddingIPBan and AddedIPBan events should be raised. </param> /// <exception cref="ArgumentNullException"> targetAddress or player is null. </exception> /// <exception cref="PlayerOpException"> Permission or configuration issues arise, or if IP is already banned. </exception> public static void BanIP([NotNull] this IPAddress targetAddress, [NotNull] Player player, [CanBeNull] string reason, bool announce, bool raiseEvents) { if (targetAddress == null) { throw new ArgumentNullException("targetAddress"); } if (player == null) { throw new ArgumentNullException("player"); } if (reason != null && reason.Trim().Length == 0) { reason = null; } // Check if player can ban IPs in general if (!player.Can(Permission.Ban, Permission.BanIP)) { PlayerOpException.ThrowPermissionMissing(player, null, "IP-ban", Permission.Ban, Permission.BanIP); } // Check if a non-bannable address was given (0.0.0.0 or 255.255.255.255) if (targetAddress.Equals(IPAddress.None) || targetAddress.Equals(IPAddress.Any)) { PlayerOpException.ThrowInvalidIP(player, null, targetAddress); } // Check if player is trying to ban self if (targetAddress.Equals(player.IP) && !player.IsSuper) { PlayerOpException.ThrowCannotTargetSelf(player, null, "IP-ban"); } lock ( BanListLock ) { CheckIfLoaded(); // Check if target is already banned IPBanInfo existingBan = Get(targetAddress); if (existingBan != null) { string msg; if (player.Can(Permission.ViewPlayerIPs)) { msg = String.Format("IP address {0} is already banned.", targetAddress); } else { msg = String.Format("Given IP address is already banned."); } string colorMsg = "&S" + msg; throw new PlayerOpException(player, null, PlayerOpExceptionCode.NoActionNeeded, msg, colorMsg); } // Check if any high-ranked players use this address PlayerInfo infoWhomPlayerCantBan = PlayerDB.FindPlayers(targetAddress) .FirstOrDefault(info => !player.Can(Permission.Ban, info.Rank)); if (infoWhomPlayerCantBan != null) { PlayerOpException.ThrowPermissionLimitIP(player, infoWhomPlayerCantBan, targetAddress); } PlayerOpException.CheckBanReason(reason, player, null, false); // Actually ban IPBanInfo banInfo = new IPBanInfo(targetAddress, null, player.Name, reason); bool result = Add(banInfo, raiseEvents); if (result) { Logger.Log(LogType.UserActivity, "{0} banned {1} (BanIP {1}). Reason: {2}", player.Name, targetAddress, reason ?? ""); if (announce) { // Announce ban on the server var can = Server.Players.Can(Permission.ViewPlayerIPs); can.Message("&W{0} was banned by {1}", targetAddress, player.ClassyName); var cant = Server.Players.Cant(Permission.ViewPlayerIPs); cant.Message("&WAn IP was banned by {0}", player.ClassyName); if (ConfigKey.AnnounceKickAndBanReasons.Enabled() && reason != null) { Server.Message("&WBanIP reason: {0}", reason); } } // Kick all players connected from address string kickReason; if (reason != null) { kickReason = String.Format("IP-Banned by {0}: {1}", player.Name, reason); } else { kickReason = String.Format("IP-Banned by {0}", player.Name); } foreach (Player other in Server.Players.FromIP(targetAddress)) { if (other.Info.BanStatus != BanStatus.IPBanExempt) { other.Kick(kickReason, LeaveReason.BanIP); // TODO: check side effects of not using DoKick } } } else { // address is already banned string msg; if (player.Can(Permission.ViewPlayerIPs)) { msg = String.Format("{0} is already banned.", targetAddress); } else { msg = "Given IP address is already banned."; } string colorMsg = "&S" + msg; throw new PlayerOpException(player, null, PlayerOpExceptionCode.NoActionNeeded, msg, colorMsg); } } }
static bool RaiseRemovingIPBanEvent( IPBanInfo info ) { var h = RemovingIPBan; if( h == null ) return false; var e = new IPBanCancellableEventArgs( info ); h( null, e ); return e.Cancel; }
internal static void Load() { lock ( BanListLock ) { if (IsLoaded) { throw new InvalidOperationException("IPBanList is already loaded!"); } if (File.Exists(Paths.IPBanListFileName)) { using (StreamReader reader = File.OpenText(Paths.IPBanListFileName)) { string headerText = reader.ReadLine(); if (headerText == null) { Logger.Log(LogType.Warning, "IPBanList.Load: IP ban file is empty."); IsLoaded = true; return; } int version = ParseHeader(headerText); if (version > FormatVersion) { Logger.Log(LogType.Warning, "IPBanList.Load: Attempting to load unsupported IPBanList format ({0}). Errors may occur.", version); } else if (version < FormatVersion) { Logger.Log(LogType.Warning, "IPBanList.Load: Converting IPBanList to a newer format (version {0} to {1}).", version, FormatVersion); } while (!reader.EndOfStream) { string line = reader.ReadLine(); if (line == null) { break; } string[] fields = line.Split(','); if (fields.Length == IPBanInfo.FieldCount) { try { IPBanInfo ban; switch (version) { case 0: ban = IPBanInfo.LoadFormat0(fields, true); break; case 1: ban = IPBanInfo.LoadFormat1(fields); break; case 2: ban = IPBanInfo.LoadFormat2(fields); break; default: return; } if (ban.Address.Equals(IPAddress.Any) || ban.Address.Equals(IPAddress.None)) { Logger.Log(LogType.Warning, "IPBanList.Load: Invalid IP address skipped."); } else { Bans.Add(ban.Address.ToString(), ban); } } catch (IOException ex) { Logger.Log(LogType.Error, "IPBanList.Load: Error while trying to read from file: {0}", ex.Message); } catch (Exception ex) { Logger.Log(LogType.Error, "IPBanList.Load: Could not parse a record: {0}", ex.Message); } } else { Logger.Log(LogType.Error, "IPBanList.Load: Corrupt record skipped ({0} fields instead of {1}): {2}", fields.Length, IPBanInfo.FieldCount, String.Join(",", fields)); } } } Logger.Log(LogType.Debug, "IPBanList.Load: Done loading IP ban list ({0} records).", Bans.Count); } else { Logger.Log(LogType.Warning, "IPBanList.Load: No IP ban file found."); } IsLoaded = true; } }
static void RaiseRemovedIPBanEvent( IPBanInfo info ) { var h = RemovedIPBan; if( h != null ) h( null, new IPBanEventArgs( info ) ); }
internal static IPBanInfo LoadFormat0( [NotNull] string[] fields, bool convertDatesToUtc ) { if( fields == null ) throw new ArgumentNullException( "fields" ); if( fields.Length != 8 ) throw new ArgumentException( "Unexpected field count", "fields" ); IPBanInfo info = new IPBanInfo { Address = IPAddress.Parse( fields[0] ), BannedBy = PlayerDB.UnescapeOldFormat( fields[1] ) }; DateTimeUtil.TryParseLocalDate( fields[2], out info.BanDate ); info.BanReason = PlayerDB.UnescapeOldFormat( fields[3] ); if( fields[4].Length > 1 ) { info.PlayerName = PlayerDB.UnescapeOldFormat( fields[4] ); } info.Attempts = Int32.Parse( fields[5] ); info.LastAttemptName = PlayerDB.UnescapeOldFormat( fields[6] ); if( info.LastAttemptName.Length == 0 ) info.LastAttemptName = null; DateTimeUtil.TryParseLocalDate( fields[7], out info.LastAttemptDate ); if( convertDatesToUtc ) { if( info.BanDate != DateTime.MinValue ) info.BanDate = info.BanDate.ToUniversalTime(); if( info.LastAttemptDate != DateTime.MinValue ) info.LastAttemptDate = info.LastAttemptDate.ToUniversalTime(); } return info; }
/// <summary> Adds a new IP Ban. </summary> /// <param name="ban"> Ban information </param> /// <returns> True if ban was added, false if it was already on the list </returns> public static bool Add( IPBanInfo ban ) { if( ban == null ) throw new ArgumentNullException( "ban" ); lock( BanListLock ) { if( Bans.ContainsKey( ban.Address.ToString() ) ) return false; if( RaiseAddingIPBanEvent( ban ) ) return false; Bans.Add( ban.Address.ToString(), ban ); RaiseAddedIPBanEvent( ban ); Save(); return true; } }
/// <summary> Bans given IP address. All players from IP are kicked. If an associated PlayerInfo is known, /// use a different overload of this method instead. Throws PlayerOpException on problems. </summary> /// <param name="targetAddress"> IP address that is being banned. </param> /// <param name="player"> Player who is banning. </param> /// <param name="reason"> Reason for ban. May be empty, if permitted by server configuration. </param> /// <param name="announce"> Whether ban should be publicly announced on the server. </param> /// <param name="raiseEvents"> Whether AddingIPBan and AddedIPBan events should be raised. </param> public static void BanIP( [NotNull] this IPAddress targetAddress, [NotNull] Player player, [CanBeNull] string reason, bool announce, bool raiseEvents ) { if( targetAddress == null ) throw new ArgumentNullException( "targetAddress" ); if( player == null ) throw new ArgumentNullException( "player" ); if( reason != null && reason.Trim().Length == 0 ) reason = null; // Check if player can ban IPs in general if( !player.Can( Permission.Ban, Permission.BanIP ) ) { PlayerOpException.ThrowPermissionMissing( player, null, "IP-ban", Permission.Ban, Permission.BanIP ); } // Check if a non-bannable address was given (0.0.0.0 or 255.255.255.255) if( targetAddress.Equals( IPAddress.None ) || targetAddress.Equals( IPAddress.Any ) ) { PlayerOpException.ThrowInvalidIP( player, null, targetAddress ); } // Check if player is trying to ban self if( targetAddress.Equals( player.IP ) && !player.IsSuper ) { PlayerOpException.ThrowCannotTargetSelf( player, null, "IP-ban" ); } // Check if target is already banned IPBanInfo existingBan = Get( targetAddress ); if( existingBan != null ) { string msg; if( player.Can( Permission.ViewPlayerIPs ) ) { msg = String.Format( "IP address {0} is already banned.", targetAddress ); } else { msg = String.Format( "Given IP address is already banned." ); } string colorMsg = "&S" + msg; throw new PlayerOpException( player, null, PlayerOpExceptionCode.NoActionNeeded, msg, colorMsg ); } // Check if any high-ranked players use this address PlayerInfo infoWhomPlayerCantBan = PlayerDB.FindPlayers( targetAddress ) .FirstOrDefault( info => !player.Can( Permission.Ban, info.Rank ) ); if( infoWhomPlayerCantBan != null ) { PlayerOpException.ThrowPermissionLimitIP( player, infoWhomPlayerCantBan, targetAddress ); } PlayerOpException.CheckBanReason( reason, player, null, false ); // Actually ban IPBanInfo banInfo = new IPBanInfo( targetAddress, null, player.Name, reason ); bool result = Add( banInfo, raiseEvents ); if( result ) { Logger.Log( LogType.UserActivity, "{0} banned {1} (BanIP {1}). Reason: {2}", player.Name, targetAddress, reason ?? "" ); if( announce ) { // Announce ban on the server var can = Server.Players.Can( Permission.ViewPlayerIPs ); can.Message( "&W{0} was banned by {1}", targetAddress, player.ClassyName ); var cant = Server.Players.Cant( Permission.ViewPlayerIPs ); cant.Message( "&WAn IP was banned by {0}", player.ClassyName ); if( ConfigKey.AnnounceKickAndBanReasons.Enabled() && reason != null ) { Server.Message( "&WBanIP reason: {0}", reason ); } } // Kick all players connected from address string kickReason; if( reason != null ) { kickReason = String.Format( "IP-Banned by {0}: {1}", player.Name, reason ); } else { kickReason = String.Format( "IP-Banned by {0}", player.Name ); } foreach( Player other in Server.Players.FromIP( targetAddress ) ) { if( other.Info.BanStatus != BanStatus.IPBanExempt ) { other.Kick( kickReason, LeaveReason.BanIP ); // TODO: check side effects of not using DoKick } } } else { // address is already banned string msg; if( player.Can( Permission.ViewPlayerIPs ) ) { msg = String.Format( "{0} is already banned.", targetAddress ); } else { msg = "Given IP address is already banned."; } string colorMsg = "&S" + msg; throw new PlayerOpException( player, null, PlayerOpExceptionCode.NoActionNeeded, msg, colorMsg ); } }
// login logic void LoginSequence() { byte opcode = reader.ReadByte(); if (opcode != (byte)InputCodes.Handshake) { world.log.Log("Session.LoginSequence: Unexpected opcode in the first packet: {0}.", LogType.Error, opcode); KickNow("Unexpected handshake message - possible protocol mismatch!"); return; } // check protocol version int clientProtocolVersion = reader.ReadByte(); if (clientProtocolVersion != Config.ProtocolVersion) { world.log.Log("Session.LoginSequence: Wrong protocol version: {0}.", LogType.Error, clientProtocolVersion); KickNow("Incompatible protocol version!"); return; } // check name for nonstandard characters string playerName = ReadString(); string verificationCode = ReadString(); reader.ReadByte(); // unused if (!Player.IsValidName(playerName)) { world.log.Log("Session.LoginSequence: Unacceptible player name: {0} ({1})", LogType.SuspiciousActivity, playerName, GetIP().ToString()); KickNow("Invalid characters in player name!"); return; } // check if player is banned player = new Player(world, playerName, this, world.map.spawn); if (player.info.banned) { player.info.ProcessFailedLogin(player); world.log.Log("Banned player {0} tried to log in.", LogType.SuspiciousActivity, player.name); world.SendToAll(PacketWriter.MakeMessage(Color.Sys + "Banned player " + player.name + " tried to log in."), player); KickNow("You were banned by " + player.info.bannedBy + " " + DateTime.Now.Subtract(player.info.banDate).Days + " days ago."); return; } // check if player's IP is banned IPBanInfo IPBanInfo = world.bans.Get(GetIP()); if (IPBanInfo != null) { player.info.ProcessFailedLogin(player); IPBanInfo.ProcessAttempt(player); world.log.Log("{0} tried to log in from a banned IP.", LogType.SuspiciousActivity, player.name); world.SendToAll(PacketWriter.MakeMessage(Color.Sys + player.name + " tried to log in from a banned IP."), null); KickNow("Your IP was banned by " + IPBanInfo.bannedBy + " " + DateTime.Now.Subtract(IPBanInfo.banDate).Days + " days ago."); return; } // verify name if (!world.server.VerifyName(player.name, verificationCode)) { string standardMessage = String.Format("Session.LoginSequence: Could not verify player name for {0} ({1}).", player.name, GetIP()); if (player.info.timesVisited == 1 || player.info.lastIP.ToString() != GetIP().ToString()) { switch (world.config.GetString("VerifyNames")) { case "Always": case "Balanced": player.info.ProcessFailedLogin(player); world.log.Log("{0} IP did not match. Player was kicked.", LogType.SuspiciousActivity, standardMessage); KickNow("Could not verify player name!"); return; case "Never": world.log.Log("{0} IP did not match. Player was allowed in anyway because VerifyNames is set to Never.", LogType.SuspiciousActivity, standardMessage); Send(PacketWriter.MakeMessage(Color.Red + "Your name could not be verified.")); world.SendToAll(PacketWriter.MakeMessage(Color.Red + "Name and IP of " + player.name + " could not be verified!"), player); break; } } else { switch (world.config.GetString("VerifyNames")) { case "Always": player.info.ProcessFailedLogin(player); world.log.Log("{0} IP matched previous records for that name. " + "Player was kicked anyway because VerifyNames is set to Always.", LogType.SuspiciousActivity, standardMessage); KickNow("Could not verify player name!"); return; case "Balanced": case "Never": world.log.Log("{0} IP matched previous records for that name. Player was allowed in.", LogType.SuspiciousActivity, standardMessage); Send(PacketWriter.MakeMessage(Color.Red + "Your name could not be verified.")); if (world.config.GetBool("AnnounceUnverifiedNames")) { world.SendToAll(PacketWriter.MakeMessage(Color.Red + "Name of " + player.name + " could not be verified, but IP matches."), player); } break; } } } // check if another player with the same name is on Player potentialClone = world.FindPlayer(player.name); if (potentialClone != null) { player.info.ProcessFailedLogin(player); world.log.Log("Session.LoginSequence: Player {0} tried to log in from two computers at once.", LogType.SuspiciousActivity, player.name); potentialClone.Message("Warning: someone just attempted to log in using your name."); KickNow("Already connected form elsewhere!"); return; } potentialClone = world.FindPlayer(GetIP()); if (potentialClone != null) { player.info.ProcessFailedLogin(player); world.log.Log("Session.LoginSequence: Player {0} tried to log in from same IP ({1}) as {2}.", LogType.SuspiciousActivity, player.name, GetIP().ToString(), potentialClone.name); potentialClone.Message("Warning: someone just attempted to log in using your IP."); KickNow("Only one connection per IP allowed!"); return; } // Register player for future block updates if (!world.RegisterPlayer(player)) { KickNow("Sorry, server is full."); return; } player.info.ProcessLogin(player); // Player is now authenticated. Send server info. writer.Write(PacketWriter.MakeHandshake(world, player)); // Start sending over the level copy writer.WriteLevelBegin(); byte[] buffer = new byte[1024]; int bytesSent = 0; // Fetch compressed map copy byte[] blockData; using (MemoryStream stream = new MemoryStream()) { world.map.GetCompressedCopy(stream, true); blockData = stream.ToArray(); } world.log.Log("Session.LoginSequence: Sending compressed level copy ({0} bytes) to {1}.", LogType.Debug, blockData.Length, player.name); while (bytesSent < blockData.Length) { int chunkSize = blockData.Length - bytesSent; if (chunkSize > 1024) { chunkSize = 1024; } Array.Copy(blockData, bytesSent, buffer, 0, chunkSize); byte progress = (byte)(100 * bytesSent / blockData.Length); // write in chunks of 1024 bytes or less writer.WriteLevelChunk(buffer, chunkSize, progress); bytesSent += chunkSize; } // Done sending over level copy writer.Write(PacketWriter.MakeLevelEnd(world.map)); // Send playerlist and add player himself writer.WriteAddEntity(255, player.name, player.pos); world.SendPlayerList(player); // Reveal newcommer to existing players world.log.Log("{0} ({1}) has joined the server.", LogType.UserActivity, player.name, player.info.playerClass.name); world.SendToAll(PacketWriter.MakeAddEntity(player, player.pos), player); world.SendToAll(PacketWriter.MakeMessage(Color.Sys + player.name + " (" + player.info.playerClass.color + player.info.playerClass.name + Color.Sys + ") has joined the server."), player); // Welcome message if (player.info.timesVisited > 1) { player.Message("Welcome back to " + world.config.GetString("ServerName")); } else { player.Message("Welcome to " + world.config.GetString("ServerName")); } player.Message("Your player class is " + player.info.playerClass.color + player.info.playerClass.name + Color.Sys + ". Type /help for details."); if (world.config.GetBool("LowLatencyMode")) { client.NoDelay = true; } // Done. world.log.Log("Session.LoginSequence: {0} is now ready.", LogType.Debug, player.name); GC.Collect(); }
// Shows ban information. // When used without arguments, shows players's own ban stats. // An optional argument allows to look at other people's ban stats. void BanInfo(Player player, Command cmd) { string name = cmd.Next(); IPAddress address; if (name == null) { name = player.name; } else if (!player.Can(Permissions.ViewOthersInfo)) { world.NoAccessMessage(player); } else if (IPAddress.TryParse(name, out address)) { IPBanInfo info = world.bans.Get(address); if (info != null) { player.Message(String.Format("{0} was banned by {1} on {2:dd MMM yyyy}.", info.address, info.bannedBy, info.banDate)); if (info.playerName != null) { player.Message(" IP ban was banned by association with " + info.playerName); } if (info.attempts > 0) { player.Message(" There have been " + info.attempts + " attempts to log in, most recently"); player.Message(String.Format(" on {0:dd MMM yyyy} by {1}.", info.lastAttemptDate, info.lastAttemptName)); } if (info.banReason != "") { player.Message(" Memo: " + info.banReason); } } else { player.Message(address.ToString() + " is currently NOT banned."); } } else { PlayerInfo info; if (!world.db.FindPlayerInfo(name, out info)) { world.ManyPlayersMessage(player, name); } else if (info != null) { if (info.banned) { player.Message("Player " + info.name + " is currently " + Color.Red + "banned."); } else { player.Message("Player " + info.name + " is currently NOT banned."); } if (info.bannedBy != "-") { player.Message(String.Format(" Last banned by {0} on {1:dd MMM yyyy}.", info.bannedBy, info.banDate)); if (info.banReason != "") { player.Message(" Ban memo: " + info.banReason); } } if (info.unbannedBy != "-") { player.Message(String.Format(" Unbanned by {0} on {1:dd MMM yyyy}.", info.unbannedBy, info.unbanDate)); if (info.unbanReason != "") { player.Message(" Unban memo: " + info.unbanReason); } } if (info.banDate != DateTime.MinValue) { TimeSpan banDuration; if (info.banned) { banDuration = DateTime.Now.Subtract(info.banDate); } else { banDuration = info.unbanDate.Subtract(info.banDate); } player.Message(String.Format(" Last ban duration: {0} days and {1:F1} hours.", (int)banDuration.TotalDays, banDuration.TotalHours)); } } else { world.NoPlayerMessage(player, name); } } }
internal static void Load() { if (File.Exists(Paths.IPBanListFileName)) { string headerText; using (StreamReader reader = File.OpenText(Paths.IPBanListFileName)) { headerText = reader.ReadLine(); // header if (headerText == null) { Logger.Log("IPBanList.Load: IP ban file is empty.", LogType.Warning); } int version = ParseHeader(headerText); while (!reader.EndOfStream) { string[] fields = reader.ReadLine().Split(','); if (fields.Length == IPBanInfo.FieldCount) { try { IPBanInfo ban; if (version == 0) { ban = IPBanInfo.LoadOldFormat(fields, true); } else { ban = IPBanInfo.Load(fields); } if (ban.Address.Equals(IPAddress.Any) || ban.Address.Equals(IPAddress.None)) { Logger.Log("IPBanList.Load: Invalid IP address skipped.", LogType.Warning); } else { Bans.Add(ban.Address.ToString(), ban); } } catch (IOException ex) { Logger.Log("IPBanList.Load: Error while trying to read from file: {0}", LogType.Error, ex.Message); } catch (Exception ex) { Logger.Log("IPBanList.Load: Could not parse a record: {0}", LogType.Error, ex.Message); } } else { Logger.Log("IPBanList.Load: Corrupt record skipped ({0} fields instead of {1}): {2}", LogType.Error, fields.Length, IPBanInfo.FieldCount, String.Join(",", fields)); } } if (version == 0) { Logger.Log("IPBanList.Load: Attempting to recover IP bans...", LogType.SystemActivity); int oldBanCount = Bans.Count; PlayerDB.RecoverIPBans(); Logger.Log("IPBanList.Load: {0} IP bans recovered.", LogType.SystemActivity, Bans.Count - oldBanCount); } } Logger.Log("IPBanList.Load: Done loading IP ban list ({0} records).", LogType.Debug, Bans.Count); } else { Logger.Log("IPBanList.Load: No IP ban file found.", LogType.Warning); } IsLoaded = true; }
/// <summary> Bans given player and their IP address. /// All players from IP are kicked. Throws PlayerOpException on problems. </summary> /// <param name="player"> Player who is banning. </param> /// <param name="reason"> Reason for ban. May be empty, if permitted by server configuration. </param> /// <param name="announce"> Whether ban should be publicly announced on the server. </param> /// <param name="raiseEvents"> Whether AddingIPBan, AddedIPBan, /// BanChanging, and BanChanged events should be raised. </param> /// <exception cref="fCraft.PlayerOpException" /> public void BanIP( [NotNull] Player player, [CanBeNull] string reason, bool announce, bool raiseEvents ) { if( player == null ) throw new ArgumentNullException( "player" ); if( reason != null && reason.Trim().Length == 0 ) reason = null; lock( actionLock ) { if( !player.Can( Permission.Ban, Permission.BanIP ) ) { PlayerOpException.ThrowPermissionMissing( player, this, "IP-ban", Permission.Ban, Permission.BanIP ); } IPAddress address = LastIP; // Check if player is trying to ban self if( player.Info == this || address.Equals( player.IP ) && !player.IsSuper ) { PlayerOpException.ThrowCannotTargetSelf( player, this, "IP-ban" ); } // Check if a non-bannable address was given (0.0.0.0 or 255.255.255.255) if( address.Equals( IPAddress.None ) || address.Equals( IPAddress.Any ) ) { PlayerOpException.ThrowInvalidIP( player, this, address ); } // Check if any high-ranked players use this address PlayerInfo infoWhomPlayerCantBan = PlayerDB.FindPlayers( address ) .FirstOrDefault( info => !player.Can( Permission.Ban, info.Rank ) ); if( infoWhomPlayerCantBan != null ) { PlayerOpException.ThrowPermissionLimitIP( player, infoWhomPlayerCantBan, address ); } // Check existing ban statuses bool needNameBan = !IsBanned; bool needIPBan = !IPBanList.Contains( address ); if( !needIPBan && !needNameBan ) { string msg, colorMsg; if( player.Can( Permission.ViewPlayerIPs ) ) { msg = String.Format( "Given player ({0}) and their IP address ({1}) are both already banned.", Name, address ); colorMsg = String.Format( "&SGiven player ({0}&S) and their IP address ({1}) are both already banned.", ClassyName, address ); } else { msg = String.Format( "Given player ({0}) and their IP address are both already banned.", Name ); colorMsg = String.Format( "&SGiven player ({0}&S) and their IP address are both already banned.", ClassyName ); } throw new PlayerOpException( player, this, PlayerOpExceptionCode.NoActionNeeded, msg, colorMsg ); } // Check if target is IPBan-exempt bool targetIsExempt = (BanStatus == BanStatus.IPBanExempt); if( !needIPBan && targetIsExempt ) { string msg = String.Format( "Given player ({0}) is exempt from IP bans. Remove the exemption and retry.", Name ); string colorMsg = String.Format( "&SGiven player ({0}&S) is exempt from IP bans. Remove the exemption and retry.", ClassyName ); throw new PlayerOpException( player, this, PlayerOpExceptionCode.TargetIsExempt, msg, colorMsg ); } PlayerOpException.CheckBanReason( reason, player, this, false ); // Ban the name if( needNameBan ) { Ban( player, reason, announce, raiseEvents ); } // Ban the IP if( needIPBan ) { IPBanInfo banInfo = new IPBanInfo( address, Name, player.Name, reason ); if( IPBanList.Add( banInfo, raiseEvents ) ) { Logger.Log( LogType.UserActivity, "{0} banned {1} (BanIP {2}). Reason: {3}", player.Name, address, Name, reason ?? "" ); // Announce ban on the server if( announce ) { var can = Server.Players.Can( Permission.ViewPlayerIPs ); can.Message( "&WPlayer {0}&W was IP-banned ({1}) by {2}", ClassyName, address, player.ClassyName ); var cant = Server.Players.Cant( Permission.ViewPlayerIPs ); cant.Message( "&WPlayer {0}&W was IP-banned by {1}", ClassyName, player.ClassyName ); if( ConfigKey.AnnounceKickAndBanReasons.Enabled() && reason != null ) { Server.Message( "&WBanIP reason: {0}", reason ); } } } else { // IP is already banned string msg, colorMsg; if( player.Can( Permission.ViewPlayerIPs ) ) { msg = String.Format( "IP of player {0} ({1}) is already banned.", Name, address ); colorMsg = String.Format( "&SIP of player {0}&S ({1}) is already banned.", Name, address ); } else { msg = String.Format( "IP of player {0} is already banned.", Name ); colorMsg = String.Format( "&SIP of player {0}&S is already banned.", ClassyName ); } throw new PlayerOpException( player, null, PlayerOpExceptionCode.NoActionNeeded, msg, colorMsg ); } } // Kick all players connected from address string kickReason; if( reason != null ) { kickReason = String.Format( "IP-Banned by {0}: {1}", player.Name, reason ); } else { kickReason = String.Format( "IP-Banned by {0}", player.Name ); } foreach( Player other in Server.Players.FromIP( address ) ) { if( other.Info.BanStatus != BanStatus.IPBanExempt ) { other.Kick( kickReason, LeaveReason.BanIP ); // TODO: check side effects of not using DoKick } } } }
public static void PrintPlayerInfo(Player player, PlayerInfo info) { Player target = Server.FindPlayerExact(info.Name); // hide online status when hidden if (target != null && !player.CanSee(target)) { target = null; } if (info.LastIP.Equals(IPAddress.None)) { player.Message("About {0}&S: Never seen before.", info.GetClassyName()); } else { if (target != null) { if (target.IsHidden) { if (player.Can(Permission.ViewPlayerIPs)) { player.Message("About {0}&S: HIDDEN. Online from {1}", info.GetClassyName(), info.LastIP); } else { player.Message("About {0}&S: HIDDEN.", info.GetClassyName()); } } else { if (player.Can(Permission.ViewPlayerIPs)) { player.Message("About {0}&S: Online now from {1}", info.GetClassyName(), info.LastIP); } else { player.Message("About {0}&S: Online now.", info.GetClassyName()); } } } else { if (player.Can(Permission.ViewPlayerIPs)) { player.Message("About {0}&S: Last seen {1} ago from {2}", info.GetClassyName(), info.TimeSinceLastSeen.ToMiniString(), info.LastIP); } else { player.Message("About {0}&S: Last seen {1} ago.", info.GetClassyName(), info.TimeSinceLastSeen.ToMiniString()); } } // Show login information player.Message(" Logged in {0} time(s) since {1:d MMM yyyy}.", info.TimesVisited, info.FirstLoginDate); } // Show ban information IPBanInfo ipBan = IPBanList.Get(info.LastIP); if (ipBan != null && info.Banned) { player.Message(" Both name and IP are {0}BANNED&S. See &H/baninfo", Color.Red); } else if (ipBan != null) { player.Message(" IP is {0}BANNED&S (but nick isn't). See &H/baninfo", Color.Red); } else if (info.Banned) { player.Message(" Nick is {0}BANNED&S (but IP isn't). See &H/baninfo", Color.Red); } if (info.LastIP.ToString() != IPAddress.None.ToString()) { // Show alts List <PlayerInfo> altNames = new List <PlayerInfo>(); int bannedAltCount = 0; foreach (PlayerInfo playerFromSameIP in PlayerDB.FindPlayers(info.LastIP, 25)) { if (playerFromSameIP != info) { altNames.Add(playerFromSameIP); if (playerFromSameIP.Banned) { bannedAltCount++; } } } if (altNames.Count > 0) { if (bannedAltCount > 0) { player.Message(" {0} accounts ({1} banned) share this IP: {2}", altNames.Count, bannedAltCount, altNames.ToArray().JoinToClassyString()); } else { player.Message(" {0} accounts share this IP: {1}", altNames.Count, altNames.ToArray().JoinToClassyString()); } } } // Stats if (info.BlocksDrawn > 500000000) { player.Message(" Built {0} and deleted {1} blocks, drew {2}M blocks, wrote {3} messages.", info.BlocksBuilt, info.BlocksDeleted, info.BlocksDrawn / 1000000, info.LinesWritten); } else if (info.BlocksDrawn > 500000) { player.Message(" Built {0} and deleted {1} blocks, drew {2}K blocks, wrote {3} messages.", info.BlocksBuilt, info.BlocksDeleted, info.BlocksDrawn / 1000, info.LinesWritten); } else if (info.BlocksDrawn > 0) { player.Message(" Built {0} and deleted {1} blocks, drew {2} blocks, wrote {3} messages.", info.BlocksBuilt, info.BlocksDeleted, info.BlocksDrawn, info.LinesWritten); } else { player.Message(" Built {0} and deleted {1} blocks, wrote {2} messages.", info.BlocksBuilt, info.BlocksDeleted, info.LinesWritten); } // More stats if (info.TimesBannedOthers > 0 || info.TimesKickedOthers > 0) { player.Message(" Kicked {0} and banned {1} players.", info.TimesKickedOthers, info.TimesBannedOthers); } if (info.TimesKicked > 0) { if (info.LastKickDate != DateTime.MinValue) { player.Message(" Got kicked {0} times. Last kick {1} ago by {2}", info.TimesKicked, info.TimeSinceLastKick.ToMiniString(), info.LastKickBy); if (info.LastKickReason.Length > 0) { player.Message(" Last kick reason: {0}", info.LastKickReason); } } else { player.Message(" Got kicked {0} times", info.TimesKicked); } } // Promotion/demotion if (!String.IsNullOrEmpty(info.RankChangedBy)) { if (info.PreviousRank == null) { player.Message(" Promoted to {0}&S by {1} {2} ago.", info.Rank.GetClassyName(), info.RankChangedBy, info.TimeSinceRankChange.ToMiniString()); } else if (info.PreviousRank < info.Rank) { player.Message(" Promoted from {0}&S to {1}&S by {2} {3} ago.", info.PreviousRank.GetClassyName(), info.Rank.GetClassyName(), info.RankChangedBy, info.TimeSinceRankChange.ToMiniString()); if (!string.IsNullOrEmpty(info.RankChangeReason)) { player.Message(" Promotion reason: {0}", info.RankChangeReason); } } else { player.Message(" Demoted from {0}&S to {1}&S by {2} {3} ago.", info.PreviousRank.GetClassyName(), info.Rank.GetClassyName(), info.RankChangedBy, info.TimeSinceRankChange.ToMiniString()); if (info.RankChangeReason.Length > 0) { player.Message(" Demotion reason: {0}", info.RankChangeReason); } } } else { player.Message(" Rank is {0}&S (default).", info.Rank.GetClassyName()); } if (info.LastIP.ToString() != IPAddress.None.ToString()) { // Time on the server TimeSpan totalTime = info.TotalTime; if (target != null) { totalTime = totalTime.Add(info.TimeSinceLastLogin); } player.Message(" Spent a total of {0:F1} hours ({1:F1} minutes) here.", totalTime.TotalHours, totalTime.TotalMinutes); } }
/// <summary> Bans given IP address and all accounts on that IP. All players from IP are kicked. /// Throws PlayerOpException on problems. </summary> /// <param name="targetAddress"> IP address that is being banned. </param> /// <param name="player"> Player who is banning. </param> /// <param name="reason"> Reason for ban. May be empty, if permitted by server configuration. </param> /// <param name="announce"> Whether ban should be publicly announced on the server. </param> /// <param name="raiseEvents"> Whether AddingIPBan, AddedIPBan, BanChanging, and BanChanged events should be raised. </param> public static void BanAll( [NotNull] this IPAddress targetAddress, [NotNull] Player player, [CanBeNull] string reason, bool announce, bool raiseEvents ) { if( targetAddress == null ) throw new ArgumentNullException( "targetAddress" ); if( player == null ) throw new ArgumentNullException( "player" ); if( reason != null && reason.Trim().Length == 0 ) reason = null; if( !player.Can( Permission.Ban, Permission.BanIP, Permission.BanAll ) ) { PlayerOpException.ThrowPermissionMissing( player, null, "ban-all", Permission.Ban, Permission.BanIP, Permission.BanAll ); } // Check if player is trying to ban self if( targetAddress.Equals( player.IP ) && !player.IsSuper ) { PlayerOpException.ThrowCannotTargetSelf( player, null, "ban-all" ); } // Check if a non-bannable address was given (0.0.0.0 or 255.255.255.255) if( targetAddress.Equals( IPAddress.None ) || targetAddress.Equals( IPAddress.Any ) ) { PlayerOpException.ThrowInvalidIP( player, null, targetAddress ); } // Check if any high-ranked players use this address PlayerInfo[] allPlayersOnIP = PlayerDB.FindPlayers( targetAddress ); PlayerInfo infoWhomPlayerCantBan = allPlayersOnIP.FirstOrDefault( info => !player.Can( Permission.Ban, info.Rank ) ); if( infoWhomPlayerCantBan != null ) { PlayerOpException.ThrowPermissionLimitIP( player, infoWhomPlayerCantBan, targetAddress ); } PlayerOpException.CheckBanReason( reason, player, null, false ); bool somethingGotBanned = false; // Ban the IP if( !Contains( targetAddress ) ) { IPBanInfo banInfo = new IPBanInfo( targetAddress, null, player.Name, reason ); if( Add( banInfo, raiseEvents ) ) { Logger.Log( LogType.UserActivity, "{0} banned {1} (BanAll {1}). Reason: {2}", player.Name, targetAddress, reason ?? "" ); // Announce ban on the server if( announce ) { var can = Server.Players.Can( Permission.ViewPlayerIPs ); can.Message( "&W{0} was banned by {1}", targetAddress, player.ClassyName ); var cant = Server.Players.Cant( Permission.ViewPlayerIPs ); cant.Message( "&WAn IP was banned by {0}", player.ClassyName ); } somethingGotBanned = true; } } // Ban individual players foreach( PlayerInfo targetAlt in allPlayersOnIP ) { if( targetAlt.BanStatus != BanStatus.NotBanned ) continue; // Raise PlayerInfo.BanChanging event PlayerInfoBanChangingEventArgs e = new PlayerInfoBanChangingEventArgs( targetAlt, player, false, reason, announce ); if( raiseEvents ) { PlayerInfo.RaiseBanChangingEvent( e ); if( e.Cancel ) continue; reason = e.Reason; } // Do the ban if( targetAlt.ProcessBan( player, player.Name, reason ) ) { if( raiseEvents ) { PlayerInfo.RaiseBanChangedEvent( e ); } // Log and announce ban Logger.Log( LogType.UserActivity, "{0} banned {1} (BanAll {2}). Reason: {3}", player.Name, targetAlt.Name, targetAddress, reason ?? "" ); if( announce ) { Server.Message( "&WPlayer {0}&W was banned by {1}&W (BanAll)", targetAlt.ClassyName, player.ClassyName ); } somethingGotBanned = true; } } // If no one ended up getting banned, quit here if( !somethingGotBanned ) { PlayerOpException.ThrowNoOneToBan( player, null, targetAddress ); } // Announce BanAll reason towards the end of all bans if( announce && ConfigKey.AnnounceKickAndBanReasons.Enabled() && reason != null ) { Server.Message( "&WBanAll reason: {0}", reason ); } // Kick all players from IP Player[] targetsOnline = Server.Players.FromIP( targetAddress ).ToArray(); if( targetsOnline.Length > 0 ) { string kickReason; if( reason != null ) { kickReason = String.Format( "Banned by {0}: {1}", player.Name, reason ); } else { kickReason = String.Format( "Banned by {0}", player.Name ); } for( int i = 0; i < targetsOnline.Length; i++ ) { targetsOnline[i].Kick( kickReason, LeaveReason.BanAll ); } } }
internal static void BanInfo(Player player, Command cmd) { string name = cmd.Next(); IPAddress address; if (name == null) { name = player.Name; } else if (!player.Can(Permission.ViewOthersInfo)) { player.NoAccessMessage(Permission.ViewOthersInfo); return; } if (Server.IsIP(name) && IPAddress.TryParse(name, out address)) { IPBanInfo info = IPBanList.Get(address); if (info != null) { player.Message("{0} was banned by {1} on {2:dd MMM yyyy}.", info.Address, info.BannedBy, info.BanDate); if (!String.IsNullOrEmpty(info.PlayerName)) { player.Message(" IP ban was banned by association with {0}", info.PlayerName); } if (info.Attempts > 0) { player.Message(" There have been {0} attempts to log in, most recently", info.Attempts); player.Message(" on {0:dd MMM yyyy} by {1}.", info.LastAttemptDate, info.LastAttemptName); } if (info.BanReason.Length > 0) { player.Message(" Ban reason: {0}", info.BanReason); } } else { player.Message("{0} is currently NOT banned.", address); } } else { PlayerInfo info; if (!PlayerDB.FindPlayerInfo(name, out info)) { player.Message("More than one player found matching \"{0}\"", name); } else if (info != null) { if (info.Banned) { player.Message("Player {0}&S is &WBANNED", info.GetClassyName()); } else { player.Message("Player {0}&S is NOT banned.", info.GetClassyName()); } if (!String.IsNullOrEmpty(info.BannedBy)) { player.Message(" Last ban by {0} on {1:dd MMM yyyy} ({2} ago).", info.BannedBy, info.BanDate, info.TimeSinceBan.ToMiniString()); if (info.BanReason.Length > 0) { player.Message(" Last ban reason: {0}", info.BanReason); } } if (!String.IsNullOrEmpty(info.UnbannedBy)) { player.Message(" Unbanned by {0} on {1:dd MMM yyyy} ({2} ago).", info.UnbannedBy, info.UnbanDate, info.TimeSinceUnban.ToMiniString()); if (info.UnbanReason.Length > 0) { player.Message(" Last unban reason: {0}", info.UnbanReason); } } if (info.BanDate != DateTime.MinValue) { TimeSpan banDuration; if (info.Banned) { banDuration = info.TimeSinceBan; } else { banDuration = info.UnbanDate.Subtract(info.BanDate); } player.Message(" Last ban duration: {0} days and {1:F1} hours.", (int)banDuration.TotalDays, banDuration.TotalHours); } } else { player.NoPlayerMessage(name); } } }