modernuo/Projects/Server/Network/Firewall/Firewall.cs
Kamron Batman e0fcde885c
fix: Fixes networking issues (#1958)
### Summary
- Puts back `EventSink.SocketConnect`.
- Reverts networking change to push the networking to a separate thread.
- Reverts changes to the firewall by removing the firewall queue.
- Fixes listeners not shutting down with the server.
- Fixes race condition causing connections to get stuck even after they are disposed.

> [!NOTE]
> **Developer Note**
> Networking has been reverted back to using the main thread instead of a background thread. This alleviated complexity and the requirement for concurrent queues all over the place.
2024-09-19 16:54:49 -07:00

111 lines
3.6 KiB
C#

/*************************************************************************
* ModernUO *
* Copyright 2019-2024 - ModernUO Development Team *
* Email: hi@modernuo.com *
* File: Firewall.cs *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
*************************************************************************/
using System;
using System.Collections.Generic;
using System.Net;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace Server.Network;
public static class Firewall
{
private static InternalValidationEntry _validationEntry;
private static readonly Dictionary<IPAddress, bool> _isBlockedCache = new();
private static readonly SortedSet<IFirewallEntry> _firewallSet = new();
public static SortedSet<IFirewallEntry> FirewallSet => _firewallSet;
internal static bool IsBlocked(IPAddress address)
{
ref var isBlocked = ref CollectionsMarshal.GetValueRefOrAddDefault(_isBlockedCache, address, out var exists);
if (exists)
{
return isBlocked;
}
if (_validationEntry == null)
{
_validationEntry = new InternalValidationEntry(address);
}
else
{
_validationEntry.Address = address;
}
// Get all entries that are lower than our validation entry
var view = _firewallSet.GetViewBetween(_firewallSet.Min, _validationEntry);
// Loop backward since there shouldn't be any entries where the Min address is higher than ours
foreach (var firewallEntry in view.Reverse())
{
if (firewallEntry.IsBlocked(_validationEntry.MinIpAddress))
{
isBlocked = true;
return true;
}
}
isBlocked = view.Max?.IsBlocked(_validationEntry.MinIpAddress) == true;
return isBlocked;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool Add(IFirewallEntry firewallEntry)
{
if (_firewallSet.Add(firewallEntry))
{
_isBlockedCache.Clear();
return true;
}
return false;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool Remove(IFirewallEntry entry)
{
if (entry == null)
{
return false;
}
if (_firewallSet.Remove(entry))
{
_isBlockedCache.Clear();
return true;
}
return false;
}
private class InternalValidationEntry : BaseFirewallEntry
{
private UInt128 _address;
public IPAddress Address
{
set => _address = value.ToUInt128();
}
public override UInt128 MinIpAddress => _address;
public override UInt128 MaxIpAddress => _address;
public InternalValidationEntry(IPAddress ipAddress) => Address = ipAddress;
}
}