28 using System.Collections.Generic;
29 using System.Reflection;
32 namespace OpenSim.Framework
42 private readonly CircularBuffer<int> _generalRequestTimes;
44 private readonly Dictionary<string, CircularBuffer<int>> _deeperInspection;
45 private readonly Dictionary<string, int> _tempBlocked;
46 private readonly Dictionary<string, int> _sessions;
47 private readonly System.Timers.Timer _forgetTimer;
48 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
49 private readonly System.Threading.ReaderWriterLockSlim _blockLockSlim =
new System.Threading.ReaderWriterLockSlim();
50 private readonly System.Threading.ReaderWriterLockSlim _sessionLockSlim =
new System.Threading.ReaderWriterLockSlim();
53 _generalRequestTimes =
new CircularBuffer<int>(options.MaxRequestsInTimeframe + 1,
true);
54 _generalRequestTimes.Put(0);
56 _deeperInspection =
new Dictionary<string, CircularBuffer<int>>();
57 _tempBlocked =
new Dictionary<string, int>();
58 _sessions =
new Dictionary<string, int>();
59 _forgetTimer =
new System.Timers.Timer();
60 _forgetTimer.Elapsed += delegate
62 _forgetTimer.Enabled =
false;
64 List<string> removes =
new List<string>();
65 _blockLockSlim.EnterReadLock();
66 foreach (
string str
in _tempBlocked.Keys)
69 Util.EnvironmentTickCountSubtract(Util.EnvironmentTickCount(),
70 _tempBlocked[str]) > 0)
73 _blockLockSlim.ExitReadLock();
74 lock (_deeperInspection)
76 _blockLockSlim.EnterWriteLock();
77 for (
int i = 0; i < removes.Count; i++)
79 _tempBlocked.Remove(removes[i]);
80 _deeperInspection.Remove(removes[i]);
81 _sessions.Remove(removes[i]);
83 _blockLockSlim.ExitWriteLock();
85 foreach (
string str
in removes)
87 m_log.InfoFormat(
"[{0}] client: {1} is no longer blocked.",
88 _options.ReportingName, str);
90 _blockLockSlim.EnterReadLock();
91 if (_tempBlocked.Count > 0)
92 _forgetTimer.Enabled =
true;
93 _blockLockSlim.ExitReadLock();
96 _forgetTimer.Interval = _options.ForgetTimeSpan.TotalMilliseconds;
107 _blockLockSlim.EnterReadLock();
108 ret = _tempBlocked.ContainsKey(
key);
109 _blockLockSlim.ExitReadLock();
121 if (_options.MaxRequestsInTimeframe < 1 || _options.RequestTimeSpan.TotalMilliseconds < 1)
124 string clientstring =
key;
126 _blockLockSlim.EnterReadLock();
127 if (_tempBlocked.ContainsKey(clientstring))
129 _blockLockSlim.ExitReadLock();
134 throw new System.Security.SecurityException(
"Throttled");
137 _blockLockSlim.ExitReadLock();
139 lock (_generalRequestTimes)
140 _generalRequestTimes.Put(Util.EnvironmentTickCount());
142 if (_options.MaxConcurrentSessions > 0)
144 int sessionscount = 0;
146 _sessionLockSlim.EnterReadLock();
147 if (_sessions.ContainsKey(key))
148 sessionscount = _sessions[key];
149 _sessionLockSlim.ExitReadLock();
151 if (sessionscount > _options.MaxConcurrentSessions)
154 lock (_deeperInspection)
156 _blockLockSlim.EnterWriteLock();
157 if (!_tempBlocked.ContainsKey(clientstring))
159 _tempBlocked.Add(clientstring,
160 Util.EnvironmentTickCount() +
161 (
int) _options.ForgetTimeSpan.TotalMilliseconds);
162 _forgetTimer.Enabled =
true;
163 m_log.WarnFormat(
"[{0}]: client: {1} is blocked for {2} milliseconds based on concurrency, X-ForwardedForAllowed status is {3}, endpoint:{4}", _options.ReportingName, clientstring, _options.ForgetTimeSpan.TotalMilliseconds, _options.AllowXForwardedFor, endpoint);
167 _tempBlocked[clientstring] = Util.EnvironmentTickCount() +
168 (
int) _options.ForgetTimeSpan.TotalMilliseconds;
169 _blockLockSlim.ExitWriteLock();
176 ProcessConcurrency(key, endpoint);
178 if (_generalRequestTimes.Size == _generalRequestTimes.Capacity &&
179 (Util.EnvironmentTickCountSubtract(Util.EnvironmentTickCount(), _generalRequestTimes.Get()) <
180 _options.RequestTimeSpan.TotalMilliseconds))
183 if (DeeperInspection(key, endpoint))
188 throw new System.Security.SecurityException(
"Throttled");
192 private void ProcessConcurrency(
string key,
string endpoint)
194 _sessionLockSlim.EnterWriteLock();
195 if (_sessions.ContainsKey(key))
196 _sessions[key] = _sessions[key] + 1;
198 _sessions.Add(
key,1);
199 _sessionLockSlim.ExitWriteLock();
203 _sessionLockSlim.EnterWriteLock();
204 if (_sessions.ContainsKey(key))
207 if (_sessions[key] <= 0)
208 _sessions.Remove(
key);
211 _sessions.Add(
key, 1);
213 _sessionLockSlim.ExitWriteLock();
222 private bool DeeperInspection(
string key,
string endpoint)
224 lock (_deeperInspection)
226 string clientstring =
key;
229 if (_deeperInspection.ContainsKey(clientstring))
231 _deeperInspection[clientstring].Put(Util.EnvironmentTickCount());
232 if (_deeperInspection[clientstring].Size == _deeperInspection[clientstring].Capacity &&
233 (Util.EnvironmentTickCountSubtract(Util.EnvironmentTickCount(), _deeperInspection[clientstring].Get()) <
234 _options.RequestTimeSpan.TotalMilliseconds))
237 _blockLockSlim.EnterWriteLock();
238 if (!_tempBlocked.ContainsKey(clientstring))
239 _tempBlocked.Add(clientstring, Util.EnvironmentTickCount() + (int)_options.ForgetTimeSpan.TotalMilliseconds);
241 _tempBlocked[clientstring] = Util.EnvironmentTickCount() + (
int)_options.ForgetTimeSpan.TotalMilliseconds;
242 _blockLockSlim.ExitWriteLock();
244 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);
253 _deeperInspection.Add(clientstring, new CircularBuffer<int>(_options.MaxRequestsInTimeframe + 1, true));
254 _deeperInspection[clientstring].Put(Util.EnvironmentTickCount());
255 _forgetTimer.Enabled = true;
265 public class BasicDosProtectorOptions
267 public int MaxRequestsInTimeframe;
268 public TimeSpan RequestTimeSpan;
269 public TimeSpan ForgetTimeSpan;
270 public bool AllowXForwardedFor;
271 public string ReportingName = "BASICDOSPROTECTOR
";
272 public BasicDOSProtector.ThrottleAction ThrottledAction = BasicDOSProtector.ThrottleAction.DoThrottledMethod;
273 public int MaxConcurrentSessions;
bool Process(string key, string endpoint)
Process the velocity of this context
void ProcessEnd(string key, string endpoint)
OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString key
bool IsBlocked(string key)
Given a string Key, Returns if that context is blocked
BasicDOSProtector(BasicDosProtectorOptions options)