## Breaking Changes * The Firewall and IP Limiter have been rewritten. Please read the notes carefully! * `TcpServer.Instances` moved back to `NetState.Instances` - sorry - it was stupid to move it to begin with. > [!Note] > Sockets that fail the IP Limiter or Firewall will be immediately and forcibly disconnected. > This means they will be stuck at "Verifying account..." if it was a real client. ### Summary - Removes firewall wildcard support. - Removes `AccessRestrictions`. - Moves Firewall/IPLimiter to the core. - Moves `TcpServer` to its own thread. - Removes the `SocketConnect` and `SocketDisconnect` event sinks. - Moves `Instances` back to `NetState.Instances`. - Fixes a long standing bug with bad handling of duplicate listener addresses. #### Firewall The firewall has been completely rewritten. There is now an "Admin Firewall" which saves to the config file. Secondarily, there is an internal firewall used exclusively by the TcpServer while processing sockets. The Admin firewall mirrors it's additions/deletions to the internal firewall by adding requests to a queue. > [!IMPORTANT] > **Wildcard firewall entries, such as `X`, `*`, `?` are not allowed.** > **Ranges in between IP classes or sextets are not allowed.** > **Please make sure to use one of the following:** > * IP Address - `192.168.1.1` > * CIDR - `192.168.1.0/24` > * Range - `192.168.1.1-192.168.1.100` #### IP Limiter The IP Limiter has been completely rewritten. The available configurations are: ```json "ipLimiter.enable": "True", "ipLimiter.maxConnectionsPerIP": 10, "ipLimiter.clearConnectionAttemptsDuration": "00:00:00:10", "ipLimiter.clearThrottledDuration": "00:00:02:00", ``` The IP Limiter is set up to prevent spamming connections from the same IP. Every time an IP connects, it is added to a connection list. After 10 attempts, the IP is added to the throttle list. To keep the system fast, the connection list is entirely wiped every 10 seconds, and the throttle list is entirely wiped every 2 minutes.
126 lines
3.5 KiB
C#
126 lines
3.5 KiB
C#
using System;
|
|
using Server.Items;
|
|
using Server.Network;
|
|
|
|
namespace Server
|
|
{
|
|
#pragma warning disable CA1052
|
|
public class LightCycle
|
|
{
|
|
public const int DayLevel = 0;
|
|
public const int NightLevel = 12;
|
|
public const int DungeonLevel = 26;
|
|
public const int JailLevel = 9;
|
|
|
|
private static int m_LevelOverride = int.MinValue;
|
|
|
|
public static int LevelOverride
|
|
{
|
|
get => m_LevelOverride;
|
|
set
|
|
{
|
|
m_LevelOverride = value;
|
|
|
|
foreach (var ns in NetState.Instances)
|
|
{
|
|
var m = ns.Mobile;
|
|
|
|
m?.CheckLightLevels(false);
|
|
}
|
|
}
|
|
}
|
|
|
|
public static void Initialize()
|
|
{
|
|
new LightCycleTimer().Start();
|
|
EventSink.Login += OnLogin;
|
|
|
|
CommandSystem.Register("GlobalLight", AccessLevel.GameMaster, Light_OnCommand);
|
|
}
|
|
|
|
[Usage("GlobalLight <value>"), Description("Sets the current global light level.")]
|
|
private static void Light_OnCommand(CommandEventArgs e)
|
|
{
|
|
if (e.Length >= 1)
|
|
{
|
|
LevelOverride = e.GetInt32(0);
|
|
e.Mobile.SendMessage($"Global light level override has been changed to {m_LevelOverride}.");
|
|
}
|
|
else
|
|
{
|
|
LevelOverride = int.MinValue;
|
|
e.Mobile.SendMessage("Global light level override has been cleared.");
|
|
}
|
|
}
|
|
|
|
public static void OnLogin(Mobile m)
|
|
{
|
|
m.CheckLightLevels(true);
|
|
}
|
|
|
|
public static int ComputeLevelFor(Mobile from)
|
|
{
|
|
if (m_LevelOverride > int.MinValue)
|
|
{
|
|
return m_LevelOverride;
|
|
}
|
|
|
|
Clock.GetTime(from.Map, from.X, from.Y, out var hours, out int minutes);
|
|
|
|
/* OSI times:
|
|
*
|
|
* Midnight -> 3:59 AM : Night
|
|
* 4:00 AM -> 11:59 PM : Day
|
|
*
|
|
* RunUO times:
|
|
*
|
|
* 10:00 PM -> 11:59 PM : Scale to night
|
|
* Midnight -> 3:59 AM : Night
|
|
* 4:00 AM -> 5:59 AM : Scale to day
|
|
* 6:00 AM -> 9:59 PM : Day
|
|
*/
|
|
|
|
return hours switch
|
|
{
|
|
< 4 => NightLevel,
|
|
< 6 => NightLevel + ((hours - 4) * 60 + minutes) * (DayLevel - NightLevel) / 120,
|
|
< 22 => DayLevel,
|
|
< 24 => DayLevel + ((hours - 22) * 60 + minutes) * (NightLevel - DayLevel) / 120,
|
|
_ => NightLevel
|
|
};
|
|
}
|
|
|
|
private class LightCycleTimer : Timer
|
|
{
|
|
public LightCycleTimer() : base(TimeSpan.FromSeconds(0), TimeSpan.FromSeconds(5.0))
|
|
{
|
|
}
|
|
|
|
protected override void OnTick()
|
|
{
|
|
foreach (var ns in NetState.Instances)
|
|
{
|
|
ns.Mobile?.CheckLightLevels(false);
|
|
}
|
|
}
|
|
}
|
|
|
|
public class NightSightTimer : Timer
|
|
{
|
|
private readonly Mobile m_Owner;
|
|
|
|
public NightSightTimer(Mobile owner) : base(TimeSpan.FromMinutes(Utility.Random(15, 25)))
|
|
{
|
|
m_Owner = owner;
|
|
}
|
|
|
|
protected override void OnTick()
|
|
{
|
|
m_Owner.EndAction<LightCycle>();
|
|
m_Owner.LightLevel = 0;
|
|
BuffInfo.RemoveBuff(m_Owner, BuffIcon.NightSight);
|
|
}
|
|
}
|
|
}
|
|
#pragma warning restore CA1052
|
|
}
|