diff --git a/WebInterface/Controllers/PrivateController.cs b/WebInterface/Controllers/PrivateController.cs index 9c2b719..8ade0bb 100644 --- a/WebInterface/Controllers/PrivateController.cs +++ b/WebInterface/Controllers/PrivateController.cs @@ -13,16 +13,19 @@ namespace WebInterface.Controllers { private readonly IPrivateServerService _privateServerService; private readonly IRateLimiterService _rateLimiterService; + private readonly ITorCheckService _torCheckService; private readonly ICustomMapService _customMapService; private readonly ILogger _logger; public PrivateController(IPrivateServerService privateServerService, IRateLimiterService rateLimiterService, + ITorCheckService torCheckService, ICustomMapService customMapService, ILogger logger) { _privateServerService = privateServerService; _rateLimiterService = rateLimiterService; + _torCheckService = torCheckService; _customMapService = customMapService; _logger = logger; } @@ -51,6 +54,9 @@ namespace WebInterface.Controllers if (!ModelState.IsValid) throw new WebInterfaceException("Something went off the rails."); + if (_torCheckService.IsTorExit(HttpContext.Connection.RemoteIpAddress)) + throw new WebInterfaceException("Requesting private servers through Tor is not allowed."); + if (!_rateLimiterService.IsRequestAllowed(HttpContext.Connection.RemoteIpAddress)) throw new WebInterfaceException("Sorry, you have requested too many servers recently, you need to wait some time."); diff --git a/WebInterface/Services/ITorCheckService.cs b/WebInterface/Services/ITorCheckService.cs new file mode 100644 index 0000000..d9f1457 --- /dev/null +++ b/WebInterface/Services/ITorCheckService.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Threading.Tasks; + +namespace WebInterface.Services +{ + public interface ITorCheckService + { + bool IsTorExit(IPAddress address); + } +} diff --git a/WebInterface/Services/TorCheckService.cs b/WebInterface/Services/TorCheckService.cs new file mode 100644 index 0000000..3432902 --- /dev/null +++ b/WebInterface/Services/TorCheckService.cs @@ -0,0 +1,54 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Threading.Tasks; + +namespace WebInterface.Services +{ + public class TorCheckService : ITorCheckService + { + private const string torExitNodesListUrl = "https://check.torproject.org/exit-addresses"; + + private static DateTime lastListUpdate = DateTime.MinValue; + private static DateTime lastUpdateFail = DateTime.MinValue; + private static string list = string.Empty; + + public bool IsTorExit(IPAddress address) + { + if (!IsListActual()) + UpdateList(); + + bool isInList = IsInList(address); + return isInList; + } + + private bool IsListActual() + { + return !(string.IsNullOrWhiteSpace(list) || DateTime.UtcNow - lastListUpdate > TimeSpan.FromDays(1)); + } + + private void UpdateList() + { + if (DateTime.UtcNow - lastUpdateFail > TimeSpan.FromMinutes(30)) + { + WebClient webClient = new WebClient(); + var listTask = webClient.DownloadStringTaskAsync(new Uri(torExitNodesListUrl)); + if (listTask.Wait(TimeSpan.FromSeconds(2))) + { + list = listTask.Result; + lastListUpdate = DateTime.UtcNow; + } + else + { + lastUpdateFail = DateTime.UtcNow; + } + } + } + + private bool IsInList(IPAddress address) + { + return list.Contains(address.ToString()); + } + } +} diff --git a/WebInterface/Startup.cs b/WebInterface/Startup.cs index 8e318da..42fd723 100644 --- a/WebInterface/Startup.cs +++ b/WebInterface/Startup.cs @@ -45,6 +45,7 @@ namespace WebInterface services.Add(new ServiceDescriptor(typeof(IStateService), typeof(StateService), ServiceLifetime.Singleton)); services.Add(new ServiceDescriptor(typeof(IPrivateServerService), typeof(PrivateServerService), ServiceLifetime.Transient)); services.Add(new ServiceDescriptor(typeof(IRateLimiterService), typeof(RateLimiterService), ServiceLifetime.Singleton)); + services.Add(new ServiceDescriptor(typeof(ITorCheckService), typeof(TorCheckService), ServiceLifetime.Singleton)); services.Add(new ServiceDescriptor(typeof(ICustomMapService), typeof(CustomMapService), ServiceLifetime.Transient)); services.Configure(options =>