Compare commits

...

11 Commits

Author SHA1 Message Date
Fernando Oliveira
b84e22e459 Merge branch 'master' of https://github.com/ffoliveira/opensimulator 2013-10-08 18:26:53 -03:00
Fernando Oliveira
2c5c8e645d Fix class name Error 2013-10-08 18:25:45 -03:00
Fernando Oliveira
442036773d Merge branch 'master' of https://github.com/nebadon2025/opensimulator 2013-10-08 09:44:43 -03:00
Fernando Oliveira
fb45331d00 Merge branch 'master' of https://github.com/ffoliveira/opensimulator
Conflicts:
	OpenSim/Data/PGSQL/PGSQLRegionData.cs
2013-10-08 02:06:36 -03:00
Fernando Oliveira
ddaaf15199 Merge pull request #5 from hack13/master
Un-Reverted Estate Name & Region Name lower() removals. Turns out there is an issue with how Postgres queries, using lower() workaround seems like solid solution.
2013-10-07 22:03:45 -07:00
CyberWrld
ebd594d7d5 Another Un-Revert for Postgres, while also fixing a typo I left behind from previous edit. 2013-10-08 00:55:43 -04:00
CyberWrld
cf8a6669d2 Un-Reverting my change due to Postgres issue with the ILIKE function, thanks to fernando for pointing it out 2013-10-08 00:52:54 -04:00
teravus
e7ea053c4a * Remove a test *cleanup* 2013-10-07 23:52:44 -05:00
teravus
1df58d04b1 * Move the BasicDOSProtector.cs to OpenSim.Framework (all useful classes belong there.....)
* Add an IsBlocked(string Key) method so it can be used more generically.   (think..   if we want to rate limit login failures, we could have a call in the Login Service to IsBlocked(uuid.ToString()) and ignore the connection if it returns true, if IsBlocked returns false, we could run the login information and if the login fails we could run the Process method to count the login failures.
2013-10-07 23:48:24 -05:00
CyberWrld
de218bdd4e Merge pull request #1 from ffoliveira/master
pulling in changes
2013-10-07 21:47:29 -07:00
teravus
75fdd6054d * Refactor
* Break out common BasicDOSProtector code into separate class.
2013-10-07 23:19:50 -05:00
10 changed files with 252 additions and 429 deletions

View File

@@ -443,7 +443,7 @@ namespace OpenSim.Data.PGSQL
public List<int> GetEstates(string search)
{
List<int> result = new List<int>();
string sql = "select \"estateID\" from estate_settings where \"EstateName\") = :EstateName";
string sql = "select \"estateID\" from estate_settings where lower(\"EstateName\") = lower(:EstateName)";
using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString))
{
conn.Open();

View File

@@ -40,11 +40,11 @@ namespace OpenSim.Data.PGSQL
/// <summary>
/// A MySQL Interface for user grid data
/// </summary>
public class MySQLHGTravelData : PGSQLGenericTableHandler<HGTravelingData>, IHGTravelingData
public class PGSQLHGTravelData : PGSQLGenericTableHandler<HGTravelingData>, IHGTravelingData
{
// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
public MySQLHGTravelData(string connectionString, string realm) : base(connectionString, realm, "HGTravelStore") { }
public PGSQLHGTravelData(string connectionString, string realm) : base(connectionString, realm, "HGTravelStore") { }
public HGTravelingData Get(UUID sessionID)
{

View File

@@ -95,10 +95,10 @@ namespace OpenSim.Data.PGSQL
public List<RegionData> Get(string regionName, UUID scopeID)
{
string sql = "select * from "+m_Realm+" where \"regionName\" ilike :regionName ";
string sql = "select * from "+m_Realm+" where lower(\"regionName\") like lower(:regionName) ";
if (scopeID != UUID.Zero)
sql += " and \"ScopeID\" = :scopeID";
sql += " order by \"regionName\"";
sql += " order by lower(\"regionName\")";
using (NpgsqlConnection conn = new NpgsqlConnection(m_ConnectionString))
using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn))

View File

@@ -0,0 +1,209 @@
/*
* 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
{
public class BasicDOSProtector
{
public enum ThrottleAction
{
DoThrottledMethod,
DoThrow
}
private readonly CircularBuffer<int> _generalRequestTimes; // General request checker
private readonly BasicDosProtectorOptions _options;
private readonly Dictionary<string, CircularBuffer<int>> _deeperInspection; // per client request checker
private readonly Dictionary<string, int> _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<int>(options.MaxRequestsInTimeframe + 1, true);
_generalRequestTimes.Put(0);
_options = options;
_deeperInspection = new Dictionary<string, CircularBuffer<int>>();
_tempBlocked = new Dictionary<string, int>();
_forgetTimer = new System.Timers.Timer();
_forgetTimer.Elapsed += delegate
{
_forgetTimer.Enabled = false;
List<string> removes = new List<string>();
_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;
}
/// <summary>
/// Given a string Key, Returns if that context is blocked
/// </summary>
/// <param name="key">A Key identifying the context</param>
/// <returns>bool Yes or No, True or False for blocked</returns>
public bool IsBlocked(string key)
{
bool ret = false;
_lockSlim.EnterReadLock();
ret = _tempBlocked.ContainsKey(key);
_lockSlim.ExitReadLock();
return ret;
}
/// <summary>
/// Process the velocity of this context
/// </summary>
/// <param name="key"></param>
/// <param name="endpoint"></param>
/// <returns></returns>
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;
}
/// <summary>
/// At this point, the rate limiting code needs to track 'per user' velocity.
/// </summary>
/// <param name="key">Context Key, string representing a rate limiting context</param>
/// <param name="endpoint"></param>
/// <returns></returns>
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<int>(_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;
}
}

View File

@@ -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
/// </remarks>
public abstract class BaseStreamHandlerBasicDOSProtector : BaseRequestHandler, IStreamedRequestHandler
{
private readonly CircularBuffer<int> _generalRequestTimes;
private readonly BasicDosProtectorOptions _options;
private readonly Dictionary<string, CircularBuffer<int>> _deeperInspection;
private readonly Dictionary<string, int> _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<int>(options.MaxRequestsInTimeframe + 1, true);
_generalRequestTimes.Put(0);
_options = options;
_deeperInspection = new Dictionary<string, CircularBuffer<int>>();
_tempBlocked = new Dictionary<string, int>();
_forgetTimer = new System.Timers.Timer();
_forgetTimer.Elapsed += delegate
{
_forgetTimer.Enabled = false;
List<string> removes = new List<string>();
_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;
}
else
result = ThrottledRequest(path, request, httpRequest, httpResponse);
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());
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<int>(_options.MaxRequestsInTimeframe + 1, true));
_deeperInspection[clientstring].Put(Util.EnvironmentTickCount());
_forgetTimer.Enabled = true;
}
}
return true;
}
private string GetRemoteAddr(IOSHttpRequest httpRequest)
{
string remoteaddr = string.Empty;

View File

@@ -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<int> _generalRequestTimes;
private readonly BasicDosProtectorOptions _options;
private readonly Dictionary<string, CircularBuffer<int>> _deeperInspection;
private readonly Dictionary<string, int> _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<int>(options.MaxRequestsInTimeframe + 1, true);
_generalRequestTimes.Put(0);
_options = options;
_deeperInspection = new Dictionary<string, CircularBuffer<int>>();
_tempBlocked = new Dictionary<string, int>();
_forgetTimer = new System.Timers.Timer();
_forgetTimer.Elapsed += delegate
{
_forgetTimer.Enabled = false;
List<string> removes = new List<string>();
_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;
else
return _throttledMethod(request);
}
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<int>(_options.MaxRequestsInTimeframe + 1, true));
_deeperInspection[clientstring].Put(Util.EnvironmentTickCount());
_forgetTimer.Enabled = true;
}
}
return true;
}
private string GetRemoteAddr(Hashtable request)
{
string remoteaddr = "";

View File

@@ -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<int> _generalRequestTimes; // General request checker
private readonly BasicDosProtectorOptions _options;
private readonly Dictionary<string, CircularBuffer<int>> _deeperInspection; // per client request checker
private readonly Dictionary<string, int> _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<int>(options.MaxRequestsInTimeframe + 1,true);
_generalRequestTimes.Put(0);
_options = options;
_deeperInspection = new Dictionary<string, CircularBuffer<int>>();
_tempBlocked = new Dictionary<string, int>();
_forgetTimer = new System.Timers.Timer();
_forgetTimer.Elapsed += delegate
{
_forgetTimer.Enabled = false;
_dosProtector = new BasicDOSProtector(_options);
List<string> removes = new List<string>();
_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<int>(_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;
}
}

View File

@@ -53,10 +53,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
{
AllowXForwardedFor = true,
ForgetTimeSpan = TimeSpan.FromMinutes(2),
MaxRequestsInTimeframe = 5,
MaxRequestsInTimeframe = 20,
ReportingName = "FRIENDSDOSPROTECTOR",
RequestTimeSpan = TimeSpan.FromSeconds(5),
ThrottledAction = ThrottleAction.DoThrottledMethod
ThrottledAction = BasicDOSProtector.ThrottleAction.DoThrottledMethod
})
{
m_FriendsModule = fmodule;

View File

@@ -173,7 +173,7 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
MaxRequestsInTimeframe = 4,
ReportingName = "MAPDOSPROTECTOR",
RequestTimeSpan = TimeSpan.FromSeconds(10),
ThrottledAction = ThrottleAction.DoThrottledMethod
ThrottledAction = BasicDOSProtector.ThrottleAction.DoThrottledMethod
}).Process);
MainServer.Instance.AddLLSDHandler(
"/MAP/MapItems/" + m_scene.RegionInfo.RegionHandle.ToString(), HandleRemoteMapItemRequest);
@@ -1094,7 +1094,7 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
{
Hashtable reply = new Hashtable();
int statuscode = 500;
reply["str_response_string"] = "I blocked you! HAHAHAHAHAHAHHAHAH";
reply["str_response_string"] = "";
reply["int_response_code"] = statuscode;
reply["content_type"] = "text/plain";
return reply;

View File

@@ -42,22 +42,14 @@ using OpenSim.Framework.Servers.HttpServer;
namespace OpenSim.Server.Handlers.Asset
{
public class AssetServerGetHandler : BaseStreamHandlerBasicDOSProtector
public class AssetServerGetHandler : BaseStreamHandler
{
// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private IAssetService m_AssetService;
public AssetServerGetHandler(IAssetService service) :
base("GET", "/assets",new BasicDosProtectorOptions()
{
AllowXForwardedFor = true,
ForgetTimeSpan = TimeSpan.FromSeconds(2),
MaxRequestsInTimeframe = 5,
ReportingName = "ASSETGETDOSPROTECTOR",
RequestTimeSpan = TimeSpan.FromSeconds(5),
ThrottledAction = ThrottleAction.DoThrottledMethod
})
base("GET", "/assets")
{
m_AssetService = service;
}