From 75fdd6054d6605877acb511b1bd794de963a15f3 Mon Sep 17 00:00:00 2001 From: teravus Date: Mon, 7 Oct 2013 23:19:50 -0500 Subject: * Refactor * Break out common BasicDOSProtector code into separate class. --- .../BaseStreamHandlerBasicDOSProtector.cs | 144 +--------------- .../Servers/HttpServer/BasicDOSProtector.cs | 181 +++++++++++++++++++++ .../HttpServer/GenericHTTPBasicDOSProtector.cs | 143 +--------------- .../Servers/HttpServer/XmlRpcBasicDOSProtector.cs | 155 ++---------------- 4 files changed, 213 insertions(+), 410 deletions(-) create mode 100644 OpenSim/Framework/Servers/HttpServer/BasicDOSProtector.cs (limited to 'OpenSim/Framework/Servers') diff --git a/OpenSim/Framework/Servers/HttpServer/BaseStreamHandlerBasicDOSProtector.cs b/OpenSim/Framework/Servers/HttpServer/BaseStreamHandlerBasicDOSProtector.cs index 8fc9a8a..9b8b8c2 100644 --- a/OpenSim/Framework/Servers/HttpServer/BaseStreamHandlerBasicDOSProtector.cs +++ b/OpenSim/Framework/Servers/HttpServer/BaseStreamHandlerBasicDOSProtector.cs @@ -25,10 +25,7 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ using OpenSim.Framework; -using System.Collections.Generic; using System.IO; -using System.Reflection; -using log4net; namespace OpenSim.Framework.Servers.HttpServer { @@ -40,61 +37,17 @@ namespace OpenSim.Framework.Servers.HttpServer /// public abstract class BaseStreamHandlerBasicDOSProtector : BaseRequestHandler, IStreamedRequestHandler { - private readonly CircularBuffer _generalRequestTimes; + private readonly BasicDosProtectorOptions _options; - private readonly Dictionary> _deeperInspection; - private readonly Dictionary _tempBlocked; - private readonly System.Timers.Timer _forgetTimer; - private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - private readonly System.Threading.ReaderWriterLockSlim _lockSlim = new System.Threading.ReaderWriterLockSlim(); + private readonly BasicDOSProtector _dosProtector; protected BaseStreamHandlerBasicDOSProtector(string httpMethod, string path, BasicDosProtectorOptions options) : this(httpMethod, path, null, null, options) {} protected BaseStreamHandlerBasicDOSProtector(string httpMethod, string path, string name, string description, BasicDosProtectorOptions options) : base(httpMethod, path, name, description) { - _generalRequestTimes = new CircularBuffer(options.MaxRequestsInTimeframe + 1, true); - _generalRequestTimes.Put(0); _options = options; - _deeperInspection = new Dictionary>(); - _tempBlocked = new Dictionary(); - _forgetTimer = new System.Timers.Timer(); - _forgetTimer.Elapsed += delegate - { - _forgetTimer.Enabled = false; - - List removes = new List(); - _lockSlim.EnterReadLock(); - foreach (string str in _tempBlocked.Keys) - { - if ( - Util.EnvironmentTickCountSubtract(Util.EnvironmentTickCount(), - _tempBlocked[str]) > 0) - removes.Add(str); - } - _lockSlim.ExitReadLock(); - lock (_deeperInspection) - { - _lockSlim.EnterWriteLock(); - for (int i = 0; i < removes.Count; i++) - { - _tempBlocked.Remove(removes[i]); - _deeperInspection.Remove(removes[i]); - } - _lockSlim.ExitWriteLock(); - } - foreach (string str in removes) - { - m_log.InfoFormat("[{0}] client: {1} is no longer blocked.", - _options.ReportingName, str); - } - _lockSlim.EnterReadLock(); - if (_tempBlocked.Count > 0) - _forgetTimer.Enabled = true; - _lockSlim.ExitReadLock(); - }; - - _forgetTimer.Interval = _options.ForgetTimeSpan.TotalMilliseconds; + _dosProtector = new BasicDOSProtector(_options); } public virtual byte[] Handle( @@ -102,58 +55,13 @@ namespace OpenSim.Framework.Servers.HttpServer { byte[] result; RequestsReceived++; - //httpRequest.Headers - if (_options.MaxRequestsInTimeframe < 1 || _options.RequestTimeSpan.TotalMilliseconds < 1) - { + if (_dosProtector.Process(GetClientString(httpRequest), GetRemoteAddr(httpRequest))) result = ProcessRequest(path, request, httpRequest, httpResponse); - RequestsHandled++; - return result; - - } - - string clientstring = GetClientString(httpRequest); - - _lockSlim.EnterReadLock(); - if (_tempBlocked.ContainsKey(clientstring)) - { - _lockSlim.ExitReadLock(); - - if (_options.ThrottledAction == ThrottleAction.DoThrottledMethod) - { - result = ThrottledRequest(path, request, httpRequest, httpResponse); - RequestsHandled++; - return result; - } - else - throw new System.Security.SecurityException("Throttled"); - } - _lockSlim.ExitReadLock(); - - _generalRequestTimes.Put(Util.EnvironmentTickCount()); + else + result = ThrottledRequest(path, request, httpRequest, httpResponse); - if (_generalRequestTimes.Size == _generalRequestTimes.Capacity && - (Util.EnvironmentTickCountSubtract(Util.EnvironmentTickCount(), _generalRequestTimes.Get()) < - _options.RequestTimeSpan.TotalMilliseconds)) - { - //Trigger deeper inspection - if (DeeperInspection(httpRequest)) - { - result = ProcessRequest(path, request, httpRequest, httpResponse); - RequestsHandled++; - return result; - } - if (_options.ThrottledAction == ThrottleAction.DoThrottledMethod) - { - result = ThrottledRequest(path, request, httpRequest, httpResponse); - RequestsHandled++; - return result; - } - else - throw new System.Security.SecurityException("Throttled"); - } - - result =ProcessRequest(path, request, httpRequest, httpResponse); + RequestsHandled++; return result; @@ -171,43 +79,7 @@ namespace OpenSim.Framework.Servers.HttpServer return new byte[0]; } - private bool DeeperInspection(IOSHttpRequest httpRequest) - { - lock (_deeperInspection) - { - string clientstring = GetClientString(httpRequest); - - - if (_deeperInspection.ContainsKey(clientstring)) - { - _deeperInspection[clientstring].Put(Util.EnvironmentTickCount()); - if (_deeperInspection[clientstring].Size == _deeperInspection[clientstring].Capacity && - (Util.EnvironmentTickCountSubtract(Util.EnvironmentTickCount(), _deeperInspection[clientstring].Get()) < - _options.RequestTimeSpan.TotalMilliseconds)) - { - _lockSlim.EnterWriteLock(); - if (!_tempBlocked.ContainsKey(clientstring)) - _tempBlocked.Add(clientstring, Util.EnvironmentTickCount() + (int)_options.ForgetTimeSpan.TotalMilliseconds); - else - _tempBlocked[clientstring] = Util.EnvironmentTickCount() + (int)_options.ForgetTimeSpan.TotalMilliseconds; - _lockSlim.ExitWriteLock(); - - m_log.WarnFormat("[{0}]: client: {1} is blocked for {2} milliseconds, X-ForwardedForAllowed status is {3}, endpoint:{4}", _options.ReportingName, clientstring, _options.ForgetTimeSpan.TotalMilliseconds, _options.AllowXForwardedFor, GetRemoteAddr(httpRequest)); - return false; - } - //else - // return true; - } - else - { - _deeperInspection.Add(clientstring, new CircularBuffer(_options.MaxRequestsInTimeframe + 1, true)); - _deeperInspection[clientstring].Put(Util.EnvironmentTickCount()); - _forgetTimer.Enabled = true; - } - - } - return true; - } + private string GetRemoteAddr(IOSHttpRequest httpRequest) { string remoteaddr = string.Empty; diff --git a/OpenSim/Framework/Servers/HttpServer/BasicDOSProtector.cs b/OpenSim/Framework/Servers/HttpServer/BasicDOSProtector.cs new file mode 100644 index 0000000..50a4ea2 --- /dev/null +++ b/OpenSim/Framework/Servers/HttpServer/BasicDOSProtector.cs @@ -0,0 +1,181 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +using System; +using System.Collections.Generic; +using System.Reflection; +using log4net; + +namespace OpenSim.Framework.Servers.HttpServer +{ + + public class BasicDOSProtector + { + public enum ThrottleAction + { + DoThrottledMethod, + DoThrow + } + private readonly CircularBuffer _generalRequestTimes; // General request checker + private readonly BasicDosProtectorOptions _options; + private readonly Dictionary> _deeperInspection; // per client request checker + private readonly Dictionary _tempBlocked; // blocked list + private readonly System.Timers.Timer _forgetTimer; // Cleanup timer + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + private readonly System.Threading.ReaderWriterLockSlim _lockSlim = new System.Threading.ReaderWriterLockSlim(); + public BasicDOSProtector(BasicDosProtectorOptions options) + { + _generalRequestTimes = new CircularBuffer(options.MaxRequestsInTimeframe + 1, true); + _generalRequestTimes.Put(0); + _options = options; + _deeperInspection = new Dictionary>(); + _tempBlocked = new Dictionary(); + _forgetTimer = new System.Timers.Timer(); + _forgetTimer.Elapsed += delegate + { + _forgetTimer.Enabled = false; + + List removes = new List(); + _lockSlim.EnterReadLock(); + foreach (string str in _tempBlocked.Keys) + { + if ( + Util.EnvironmentTickCountSubtract(Util.EnvironmentTickCount(), + _tempBlocked[str]) > 0) + removes.Add(str); + } + _lockSlim.ExitReadLock(); + lock (_deeperInspection) + { + _lockSlim.EnterWriteLock(); + for (int i = 0; i < removes.Count; i++) + { + _tempBlocked.Remove(removes[i]); + _deeperInspection.Remove(removes[i]); + } + _lockSlim.ExitWriteLock(); + } + foreach (string str in removes) + { + m_log.InfoFormat("[{0}] client: {1} is no longer blocked.", + _options.ReportingName, str); + } + _lockSlim.EnterReadLock(); + if (_tempBlocked.Count > 0) + _forgetTimer.Enabled = true; + _lockSlim.ExitReadLock(); + }; + + _forgetTimer.Interval = _options.ForgetTimeSpan.TotalMilliseconds; + } + public bool Process(string key, string endpoint) + { + if (_options.MaxRequestsInTimeframe < 1 || _options.RequestTimeSpan.TotalMilliseconds < 1) + return true; + + string clientstring = key; + + _lockSlim.EnterReadLock(); + if (_tempBlocked.ContainsKey(clientstring)) + { + _lockSlim.ExitReadLock(); + + if (_options.ThrottledAction == ThrottleAction.DoThrottledMethod) + return false; + else + throw new System.Security.SecurityException("Throttled"); + } + _lockSlim.ExitReadLock(); + + _generalRequestTimes.Put(Util.EnvironmentTickCount()); + + if (_generalRequestTimes.Size == _generalRequestTimes.Capacity && + (Util.EnvironmentTickCountSubtract(Util.EnvironmentTickCount(), _generalRequestTimes.Get()) < + _options.RequestTimeSpan.TotalMilliseconds)) + { + //Trigger deeper inspection + if (DeeperInspection(key, endpoint)) + return true; + if (_options.ThrottledAction == ThrottleAction.DoThrottledMethod) + return false; + else + throw new System.Security.SecurityException("Throttled"); + } + return true; + } + private bool DeeperInspection(string key, string endpoint) + { + lock (_deeperInspection) + { + string clientstring = key; + + + if (_deeperInspection.ContainsKey(clientstring)) + { + _deeperInspection[clientstring].Put(Util.EnvironmentTickCount()); + if (_deeperInspection[clientstring].Size == _deeperInspection[clientstring].Capacity && + (Util.EnvironmentTickCountSubtract(Util.EnvironmentTickCount(), _deeperInspection[clientstring].Get()) < + _options.RequestTimeSpan.TotalMilliseconds)) + { + //Looks like we're over the limit + _lockSlim.EnterWriteLock(); + if (!_tempBlocked.ContainsKey(clientstring)) + _tempBlocked.Add(clientstring, Util.EnvironmentTickCount() + (int)_options.ForgetTimeSpan.TotalMilliseconds); + else + _tempBlocked[clientstring] = Util.EnvironmentTickCount() + (int)_options.ForgetTimeSpan.TotalMilliseconds; + _lockSlim.ExitWriteLock(); + + m_log.WarnFormat("[{0}]: client: {1} is blocked for {2} milliseconds, X-ForwardedForAllowed status is {3}, endpoint:{4}", _options.ReportingName, clientstring, _options.ForgetTimeSpan.TotalMilliseconds, _options.AllowXForwardedFor, endpoint); + + return false; + } + //else + // return true; + } + else + { + _deeperInspection.Add(clientstring, new CircularBuffer(_options.MaxRequestsInTimeframe + 1, true)); + _deeperInspection[clientstring].Put(Util.EnvironmentTickCount()); + _forgetTimer.Enabled = true; + } + + } + return true; + } + + } + + + public class BasicDosProtectorOptions + { + public int MaxRequestsInTimeframe; + public TimeSpan RequestTimeSpan; + public TimeSpan ForgetTimeSpan; + public bool AllowXForwardedFor; + public string ReportingName = "BASICDOSPROTECTOR"; + public BasicDOSProtector.ThrottleAction ThrottledAction = BasicDOSProtector.ThrottleAction.DoThrottledMethod; + } +} diff --git a/OpenSim/Framework/Servers/HttpServer/GenericHTTPBasicDOSProtector.cs b/OpenSim/Framework/Servers/HttpServer/GenericHTTPBasicDOSProtector.cs index 5fc999a..39c98b4 100644 --- a/OpenSim/Framework/Servers/HttpServer/GenericHTTPBasicDOSProtector.cs +++ b/OpenSim/Framework/Servers/HttpServer/GenericHTTPBasicDOSProtector.cs @@ -25,13 +25,7 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -using System; using System.Collections; -using System.Collections.Generic; -using System.Reflection; -using System.Net; -using OpenSim.Framework; -using log4net; namespace OpenSim.Framework.Servers.HttpServer { @@ -39,147 +33,26 @@ namespace OpenSim.Framework.Servers.HttpServer { private readonly GenericHTTPMethod _normalMethod; private readonly GenericHTTPMethod _throttledMethod; - private readonly CircularBuffer _generalRequestTimes; + private readonly BasicDosProtectorOptions _options; - private readonly Dictionary> _deeperInspection; - private readonly Dictionary _tempBlocked; - private readonly System.Timers.Timer _forgetTimer; - private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - private readonly System.Threading.ReaderWriterLockSlim _lockSlim = new System.Threading.ReaderWriterLockSlim(); + private readonly BasicDOSProtector _dosProtector; public GenericHTTPDOSProtector(GenericHTTPMethod normalMethod, GenericHTTPMethod throttledMethod, BasicDosProtectorOptions options) { _normalMethod = normalMethod; _throttledMethod = throttledMethod; - _generalRequestTimes = new CircularBuffer(options.MaxRequestsInTimeframe + 1, true); - _generalRequestTimes.Put(0); + _options = options; - _deeperInspection = new Dictionary>(); - _tempBlocked = new Dictionary(); - _forgetTimer = new System.Timers.Timer(); - _forgetTimer.Elapsed += delegate - { - _forgetTimer.Enabled = false; - - List removes = new List(); - _lockSlim.EnterReadLock(); - foreach (string str in _tempBlocked.Keys) - { - if ( - Util.EnvironmentTickCountSubtract(Util.EnvironmentTickCount(), - _tempBlocked[str]) > 0) - removes.Add(str); - } - _lockSlim.ExitReadLock(); - lock (_deeperInspection) - { - _lockSlim.EnterWriteLock(); - for (int i = 0; i < removes.Count; i++) - { - _tempBlocked.Remove(removes[i]); - _deeperInspection.Remove(removes[i]); - } - _lockSlim.ExitWriteLock(); - } - foreach (string str in removes) - { - m_log.InfoFormat("[{0}] client: {1} is no longer blocked.", - _options.ReportingName, str); - } - _lockSlim.EnterReadLock(); - if (_tempBlocked.Count > 0) - _forgetTimer.Enabled = true; - _lockSlim.ExitReadLock(); - }; - - _forgetTimer.Interval = _options.ForgetTimeSpan.TotalMilliseconds; + _dosProtector = new BasicDOSProtector(_options); } public Hashtable Process(Hashtable request) { - if (_options.MaxRequestsInTimeframe < 1) + if (_dosProtector.Process(GetClientString(request), GetRemoteAddr(request))) return _normalMethod(request); - if (_options.RequestTimeSpan.TotalMilliseconds < 1) - return _normalMethod(request); - - string clientstring = GetClientString(request); - - _lockSlim.EnterReadLock(); - if (_tempBlocked.ContainsKey(clientstring)) - { - _lockSlim.ExitReadLock(); - - if (_options.ThrottledAction == ThrottleAction.DoThrottledMethod) - return _throttledMethod(request); - else - throw new System.Security.SecurityException("Throttled"); - } - _lockSlim.ExitReadLock(); - - _generalRequestTimes.Put(Util.EnvironmentTickCount()); - - if (_generalRequestTimes.Size == _generalRequestTimes.Capacity && - (Util.EnvironmentTickCountSubtract(Util.EnvironmentTickCount(), _generalRequestTimes.Get()) < - _options.RequestTimeSpan.TotalMilliseconds)) - { - //Trigger deeper inspection - if (DeeperInspection(request)) - return _normalMethod(request); - if (_options.ThrottledAction == ThrottleAction.DoThrottledMethod) - return _throttledMethod(request); - else - throw new System.Security.SecurityException("Throttled"); - } - Hashtable resp = null; - try - { - resp = _normalMethod(request); - } - catch (Exception) - { - - throw; - } - - return resp; - } - private bool DeeperInspection(Hashtable request) - { - lock (_deeperInspection) - { - string clientstring = GetClientString(request); - - - if (_deeperInspection.ContainsKey(clientstring)) - { - _deeperInspection[clientstring].Put(Util.EnvironmentTickCount()); - if (_deeperInspection[clientstring].Size == _deeperInspection[clientstring].Capacity && - (Util.EnvironmentTickCountSubtract(Util.EnvironmentTickCount(), _deeperInspection[clientstring].Get()) < - _options.RequestTimeSpan.TotalMilliseconds)) - { - _lockSlim.EnterWriteLock(); - if (!_tempBlocked.ContainsKey(clientstring)) - _tempBlocked.Add(clientstring, Util.EnvironmentTickCount() + (int)_options.ForgetTimeSpan.TotalMilliseconds); - else - _tempBlocked[clientstring] = Util.EnvironmentTickCount() + (int)_options.ForgetTimeSpan.TotalMilliseconds; - _lockSlim.ExitWriteLock(); - - m_log.WarnFormat("[{0}]: client: {1} is blocked for {2} milliseconds, X-ForwardedForAllowed status is {3}, endpoint:{4}", _options.ReportingName, clientstring, _options.ForgetTimeSpan.TotalMilliseconds, _options.AllowXForwardedFor, GetRemoteAddr(request)); - return false; - } - //else - // return true; - } - else - { - _deeperInspection.Add(clientstring, new CircularBuffer(_options.MaxRequestsInTimeframe + 1, true)); - _deeperInspection[clientstring].Put(Util.EnvironmentTickCount()); - _forgetTimer.Enabled = true; - } - - } - return true; + else + return _throttledMethod(request); } - + private string GetRemoteAddr(Hashtable request) { string remoteaddr = ""; diff --git a/OpenSim/Framework/Servers/HttpServer/XmlRpcBasicDOSProtector.cs b/OpenSim/Framework/Servers/HttpServer/XmlRpcBasicDOSProtector.cs index ae59c95..bc7efb6 100644 --- a/OpenSim/Framework/Servers/HttpServer/XmlRpcBasicDOSProtector.cs +++ b/OpenSim/Framework/Servers/HttpServer/XmlRpcBasicDOSProtector.cs @@ -25,162 +25,42 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -using System; -using System.Collections.Generic; -using System.Reflection; using System.Net; using Nwc.XmlRpc; using OpenSim.Framework; -using log4net; + namespace OpenSim.Framework.Servers.HttpServer { - public enum ThrottleAction - { - DoThrottledMethod, - DoThrow - } - public class XmlRpcBasicDOSProtector { private readonly XmlRpcMethod _normalMethod; private readonly XmlRpcMethod _throttledMethod; - private readonly CircularBuffer _generalRequestTimes; // General request checker + private readonly BasicDosProtectorOptions _options; - private readonly Dictionary> _deeperInspection; // per client request checker - private readonly Dictionary _tempBlocked; // blocked list - private readonly System.Timers.Timer _forgetTimer; // Cleanup timer - private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - private readonly System.Threading.ReaderWriterLockSlim _lockSlim = new System.Threading.ReaderWriterLockSlim(); + private readonly BasicDOSProtector _dosProtector; public XmlRpcBasicDOSProtector(XmlRpcMethod normalMethod, XmlRpcMethod throttledMethod,BasicDosProtectorOptions options) { _normalMethod = normalMethod; _throttledMethod = throttledMethod; - _generalRequestTimes = new CircularBuffer(options.MaxRequestsInTimeframe + 1,true); - _generalRequestTimes.Put(0); + _options = options; - _deeperInspection = new Dictionary>(); - _tempBlocked = new Dictionary(); - _forgetTimer = new System.Timers.Timer(); - _forgetTimer.Elapsed += delegate - { - _forgetTimer.Enabled = false; + _dosProtector = new BasicDOSProtector(_options); - List removes = new List(); - _lockSlim.EnterReadLock(); - foreach (string str in _tempBlocked.Keys) - { - if ( - Util.EnvironmentTickCountSubtract(Util.EnvironmentTickCount(), - _tempBlocked[str]) > 0) - removes.Add(str); - } - _lockSlim.ExitReadLock(); - lock (_deeperInspection) - { - _lockSlim.EnterWriteLock(); - for (int i = 0; i < removes.Count; i++) - { - _tempBlocked.Remove(removes[i]); - _deeperInspection.Remove(removes[i]); - } - _lockSlim.ExitWriteLock(); - } - foreach (string str in removes) - { - m_log.InfoFormat("[{0}] client: {1} is no longer blocked.", - _options.ReportingName, str); - } - _lockSlim.EnterReadLock(); - if (_tempBlocked.Count > 0) - _forgetTimer.Enabled = true; - _lockSlim.ExitReadLock(); - }; - - _forgetTimer.Interval = _options.ForgetTimeSpan.TotalMilliseconds; } public XmlRpcResponse Process(XmlRpcRequest request, IPEndPoint client) { - // If these are set like this, this is disabled - if (_options.MaxRequestsInTimeframe < 1 || _options.RequestTimeSpan.TotalMilliseconds < 1) - return _normalMethod(request, client); - - string clientstring = GetClientString(request, client); - - _lockSlim.EnterReadLock(); - if (_tempBlocked.ContainsKey(clientstring)) - { - _lockSlim.ExitReadLock(); - if (_options.ThrottledAction == ThrottleAction.DoThrottledMethod) - return _throttledMethod(request, client); - else - throw new System.Security.SecurityException("Throttled"); - } - _lockSlim.ExitReadLock(); - - _generalRequestTimes.Put(Util.EnvironmentTickCount()); - - if (_generalRequestTimes.Size == _generalRequestTimes.Capacity && - (Util.EnvironmentTickCountSubtract(Util.EnvironmentTickCount(), _generalRequestTimes.Get()) < - _options.RequestTimeSpan.TotalMilliseconds)) - { - //Trigger deeper inspection - if (DeeperInspection(request, client)) - return _normalMethod(request, client); - if (_options.ThrottledAction == ThrottleAction.DoThrottledMethod) - return _throttledMethod(request, client); - else - throw new System.Security.SecurityException("Throttled"); - } XmlRpcResponse resp = null; - - resp = _normalMethod(request, client); - + if (_dosProtector.Process(GetClientString(request, client), GetEndPoint(request, client))) + resp = _normalMethod(request, client); + else + resp = _throttledMethod(request, client); + return resp; } - // If the service is getting more hits per expected timeframe then it starts to separate them out by client - private bool DeeperInspection(XmlRpcRequest request, IPEndPoint client) - { - lock (_deeperInspection) - { - string clientstring = GetClientString(request, client); - - - if (_deeperInspection.ContainsKey(clientstring)) - { - _deeperInspection[clientstring].Put(Util.EnvironmentTickCount()); - if (_deeperInspection[clientstring].Size == _deeperInspection[clientstring].Capacity && - (Util.EnvironmentTickCountSubtract(Util.EnvironmentTickCount(), _deeperInspection[clientstring].Get()) < - _options.RequestTimeSpan.TotalMilliseconds)) - { - //Looks like we're over the limit - _lockSlim.EnterWriteLock(); - if (!_tempBlocked.ContainsKey(clientstring)) - _tempBlocked.Add(clientstring, Util.EnvironmentTickCount() + (int)_options.ForgetTimeSpan.TotalMilliseconds); - else - _tempBlocked[clientstring] = Util.EnvironmentTickCount() + (int)_options.ForgetTimeSpan.TotalMilliseconds; - _lockSlim.ExitWriteLock(); - - m_log.WarnFormat("[{0}]: client: {1} is blocked for {2} milliseconds, X-ForwardedForAllowed status is {3}, endpoint:{4}",_options.ReportingName,clientstring,_options.ForgetTimeSpan.TotalMilliseconds, _options.AllowXForwardedFor, client.Address); - - return false; - } - //else - // return true; - } - else - { - _deeperInspection.Add(clientstring, new CircularBuffer(_options.MaxRequestsInTimeframe + 1, true)); - _deeperInspection[clientstring].Put(Util.EnvironmentTickCount()); - _forgetTimer.Enabled = true; - } - - } - return true; - } private string GetClientString(XmlRpcRequest request, IPEndPoint client) { string clientstring; @@ -197,15 +77,12 @@ namespace OpenSim.Framework.Servers.HttpServer return clientstring; } - } + private string GetEndPoint(XmlRpcRequest request, IPEndPoint client) + { + return client.Address.ToString(); + } - public class BasicDosProtectorOptions - { - public int MaxRequestsInTimeframe; - public TimeSpan RequestTimeSpan; - public TimeSpan ForgetTimeSpan; - public bool AllowXForwardedFor; - public string ReportingName = "BASICDOSPROTECTOR"; - public ThrottleAction ThrottledAction = ThrottleAction.DoThrottledMethod; } + + } -- cgit v1.1