aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Framework/BasicDOSProtector.cs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--OpenSim/Framework/BasicDOSProtector.cs96
1 files changed, 81 insertions, 15 deletions
diff --git a/OpenSim/Framework/BasicDOSProtector.cs b/OpenSim/Framework/BasicDOSProtector.cs
index b470161..89bfa94 100644
--- a/OpenSim/Framework/BasicDOSProtector.cs
+++ b/OpenSim/Framework/BasicDOSProtector.cs
@@ -43,9 +43,11 @@ namespace OpenSim.Framework
43 private readonly BasicDosProtectorOptions _options; 43 private readonly BasicDosProtectorOptions _options;
44 private readonly Dictionary<string, CircularBuffer<int>> _deeperInspection; // per client request checker 44 private readonly Dictionary<string, CircularBuffer<int>> _deeperInspection; // per client request checker
45 private readonly Dictionary<string, int> _tempBlocked; // blocked list 45 private readonly Dictionary<string, int> _tempBlocked; // blocked list
46 private readonly Dictionary<string, int> _sessions;
46 private readonly System.Timers.Timer _forgetTimer; // Cleanup timer 47 private readonly System.Timers.Timer _forgetTimer; // Cleanup timer
47 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 48 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
48 private readonly System.Threading.ReaderWriterLockSlim _lockSlim = new System.Threading.ReaderWriterLockSlim(); 49 private readonly System.Threading.ReaderWriterLockSlim _blockLockSlim = new System.Threading.ReaderWriterLockSlim();
50 private readonly System.Threading.ReaderWriterLockSlim _sessionLockSlim = new System.Threading.ReaderWriterLockSlim();
49 public BasicDOSProtector(BasicDosProtectorOptions options) 51 public BasicDOSProtector(BasicDosProtectorOptions options)
50 { 52 {
51 _generalRequestTimes = new CircularBuffer<int>(options.MaxRequestsInTimeframe + 1, true); 53 _generalRequestTimes = new CircularBuffer<int>(options.MaxRequestsInTimeframe + 1, true);
@@ -53,13 +55,14 @@ namespace OpenSim.Framework
53 _options = options; 55 _options = options;
54 _deeperInspection = new Dictionary<string, CircularBuffer<int>>(); 56 _deeperInspection = new Dictionary<string, CircularBuffer<int>>();
55 _tempBlocked = new Dictionary<string, int>(); 57 _tempBlocked = new Dictionary<string, int>();
58 _sessions = new Dictionary<string, int>();
56 _forgetTimer = new System.Timers.Timer(); 59 _forgetTimer = new System.Timers.Timer();
57 _forgetTimer.Elapsed += delegate 60 _forgetTimer.Elapsed += delegate
58 { 61 {
59 _forgetTimer.Enabled = false; 62 _forgetTimer.Enabled = false;
60 63
61 List<string> removes = new List<string>(); 64 List<string> removes = new List<string>();
62 _lockSlim.EnterReadLock(); 65 _blockLockSlim.EnterReadLock();
63 foreach (string str in _tempBlocked.Keys) 66 foreach (string str in _tempBlocked.Keys)
64 { 67 {
65 if ( 68 if (
@@ -67,26 +70,27 @@ namespace OpenSim.Framework
67 _tempBlocked[str]) > 0) 70 _tempBlocked[str]) > 0)
68 removes.Add(str); 71 removes.Add(str);
69 } 72 }
70 _lockSlim.ExitReadLock(); 73 _blockLockSlim.ExitReadLock();
71 lock (_deeperInspection) 74 lock (_deeperInspection)
72 { 75 {
73 _lockSlim.EnterWriteLock(); 76 _blockLockSlim.EnterWriteLock();
74 for (int i = 0; i < removes.Count; i++) 77 for (int i = 0; i < removes.Count; i++)
75 { 78 {
76 _tempBlocked.Remove(removes[i]); 79 _tempBlocked.Remove(removes[i]);
77 _deeperInspection.Remove(removes[i]); 80 _deeperInspection.Remove(removes[i]);
81 _sessions.Remove(removes[i]);
78 } 82 }
79 _lockSlim.ExitWriteLock(); 83 _blockLockSlim.ExitWriteLock();
80 } 84 }
81 foreach (string str in removes) 85 foreach (string str in removes)
82 { 86 {
83 m_log.InfoFormat("[{0}] client: {1} is no longer blocked.", 87 m_log.InfoFormat("[{0}] client: {1} is no longer blocked.",
84 _options.ReportingName, str); 88 _options.ReportingName, str);
85 } 89 }
86 _lockSlim.EnterReadLock(); 90 _blockLockSlim.EnterReadLock();
87 if (_tempBlocked.Count > 0) 91 if (_tempBlocked.Count > 0)
88 _forgetTimer.Enabled = true; 92 _forgetTimer.Enabled = true;
89 _lockSlim.ExitReadLock(); 93 _blockLockSlim.ExitReadLock();
90 }; 94 };
91 95
92 _forgetTimer.Interval = _options.ForgetTimeSpan.TotalMilliseconds; 96 _forgetTimer.Interval = _options.ForgetTimeSpan.TotalMilliseconds;
@@ -100,9 +104,9 @@ namespace OpenSim.Framework
100 public bool IsBlocked(string key) 104 public bool IsBlocked(string key)
101 { 105 {
102 bool ret = false; 106 bool ret = false;
103 _lockSlim.EnterReadLock(); 107 _blockLockSlim.EnterReadLock();
104 ret = _tempBlocked.ContainsKey(key); 108 ret = _tempBlocked.ContainsKey(key);
105 _lockSlim.ExitReadLock(); 109 _blockLockSlim.ExitReadLock();
106 return ret; 110 return ret;
107 } 111 }
108 112
@@ -119,20 +123,58 @@ namespace OpenSim.Framework
119 123
120 string clientstring = key; 124 string clientstring = key;
121 125
122 _lockSlim.EnterReadLock(); 126 _blockLockSlim.EnterReadLock();
123 if (_tempBlocked.ContainsKey(clientstring)) 127 if (_tempBlocked.ContainsKey(clientstring))
124 { 128 {
125 _lockSlim.ExitReadLock(); 129 _blockLockSlim.ExitReadLock();
126 130
127 if (_options.ThrottledAction == ThrottleAction.DoThrottledMethod) 131 if (_options.ThrottledAction == ThrottleAction.DoThrottledMethod)
128 return false; 132 return false;
129 else 133 else
130 throw new System.Security.SecurityException("Throttled"); 134 throw new System.Security.SecurityException("Throttled");
131 } 135 }
132 _lockSlim.ExitReadLock(); 136
137 _blockLockSlim.ExitReadLock();
133 138
134 _generalRequestTimes.Put(Util.EnvironmentTickCount()); 139 lock (_generalRequestTimes)
140 _generalRequestTimes.Put(Util.EnvironmentTickCount());
135 141
142 if (_options.MaxConcurrentSessions > 0)
143 {
144 int sessionscount = 0;
145
146 _sessionLockSlim.EnterReadLock();
147 if (_sessions.ContainsKey(key))
148 sessionscount = _sessions[key];
149 _sessionLockSlim.ExitReadLock();
150
151 if (sessionscount > _options.MaxConcurrentSessions)
152 {
153 // Add to blocking and cleanup methods
154 lock (_deeperInspection)
155 {
156 _blockLockSlim.EnterWriteLock();
157 if (!_tempBlocked.ContainsKey(clientstring))
158 {
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);
164
165 }
166 else
167 _tempBlocked[clientstring] = Util.EnvironmentTickCount() +
168 (int) _options.ForgetTimeSpan.TotalMilliseconds;
169 _blockLockSlim.ExitWriteLock();
170
171 }
172
173
174 }
175 else
176 ProcessConcurrency(key, endpoint);
177 }
136 if (_generalRequestTimes.Size == _generalRequestTimes.Capacity && 178 if (_generalRequestTimes.Size == _generalRequestTimes.Capacity &&
137 (Util.EnvironmentTickCountSubtract(Util.EnvironmentTickCount(), _generalRequestTimes.Get()) < 179 (Util.EnvironmentTickCountSubtract(Util.EnvironmentTickCount(), _generalRequestTimes.Get()) <
138 _options.RequestTimeSpan.TotalMilliseconds)) 180 _options.RequestTimeSpan.TotalMilliseconds))
@@ -147,6 +189,29 @@ namespace OpenSim.Framework
147 } 189 }
148 return true; 190 return true;
149 } 191 }
192 private void ProcessConcurrency(string key, string endpoint)
193 {
194 _sessionLockSlim.EnterWriteLock();
195 if (_sessions.ContainsKey(key))
196 _sessions[key] = _sessions[key] + 1;
197 else
198 _sessions.Add(key,1);
199 _sessionLockSlim.ExitWriteLock();
200 }
201 public void ProcessEnd(string key, string endpoint)
202 {
203 _sessionLockSlim.EnterWriteLock();
204 if (_sessions.ContainsKey(key))
205 {
206 _sessions[key]--;
207 if (_sessions[key] <= 0)
208 _sessions.Remove(key);
209 }
210 else
211 _sessions.Add(key, 1);
212
213 _sessionLockSlim.ExitWriteLock();
214 }
150 215
151 /// <summary> 216 /// <summary>
152 /// At this point, the rate limiting code needs to track 'per user' velocity. 217 /// At this point, the rate limiting code needs to track 'per user' velocity.
@@ -169,12 +234,12 @@ namespace OpenSim.Framework
169 _options.RequestTimeSpan.TotalMilliseconds)) 234 _options.RequestTimeSpan.TotalMilliseconds))
170 { 235 {
171 //Looks like we're over the limit 236 //Looks like we're over the limit
172 _lockSlim.EnterWriteLock(); 237 _blockLockSlim.EnterWriteLock();
173 if (!_tempBlocked.ContainsKey(clientstring)) 238 if (!_tempBlocked.ContainsKey(clientstring))
174 _tempBlocked.Add(clientstring, Util.EnvironmentTickCount() + (int)_options.ForgetTimeSpan.TotalMilliseconds); 239 _tempBlocked.Add(clientstring, Util.EnvironmentTickCount() + (int)_options.ForgetTimeSpan.TotalMilliseconds);
175 else 240 else
176 _tempBlocked[clientstring] = Util.EnvironmentTickCount() + (int)_options.ForgetTimeSpan.TotalMilliseconds; 241 _tempBlocked[clientstring] = Util.EnvironmentTickCount() + (int)_options.ForgetTimeSpan.TotalMilliseconds;
177 _lockSlim.ExitWriteLock(); 242 _blockLockSlim.ExitWriteLock();
178 243
179 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); 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);
180 245
@@ -205,5 +270,6 @@ namespace OpenSim.Framework
205 public bool AllowXForwardedFor; 270 public bool AllowXForwardedFor;
206 public string ReportingName = "BASICDOSPROTECTOR"; 271 public string ReportingName = "BASICDOSPROTECTOR";
207 public BasicDOSProtector.ThrottleAction ThrottledAction = BasicDOSProtector.ThrottleAction.DoThrottledMethod; 272 public BasicDOSProtector.ThrottleAction ThrottledAction = BasicDOSProtector.ThrottleAction.DoThrottledMethod;
273 public int MaxConcurrentSessions;
208 } 274 }
209} 275}