aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Framework/Servers/HttpServer/XmlRpcBasicDOSProtector.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Framework/Servers/HttpServer/XmlRpcBasicDOSProtector.cs')
-rw-r--r--OpenSim/Framework/Servers/HttpServer/XmlRpcBasicDOSProtector.cs155
1 files changed, 16 insertions, 139 deletions
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 @@
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */ 26 */
27 27
28using System;
29using System.Collections.Generic;
30using System.Reflection;
31using System.Net; 28using System.Net;
32using Nwc.XmlRpc; 29using Nwc.XmlRpc;
33using OpenSim.Framework; 30using OpenSim.Framework;
34using log4net; 31
35 32
36namespace OpenSim.Framework.Servers.HttpServer 33namespace OpenSim.Framework.Servers.HttpServer
37{ 34{
38 public enum ThrottleAction
39 {
40 DoThrottledMethod,
41 DoThrow
42 }
43
44 public class XmlRpcBasicDOSProtector 35 public class XmlRpcBasicDOSProtector
45 { 36 {
46 private readonly XmlRpcMethod _normalMethod; 37 private readonly XmlRpcMethod _normalMethod;
47 private readonly XmlRpcMethod _throttledMethod; 38 private readonly XmlRpcMethod _throttledMethod;
48 private readonly CircularBuffer<int> _generalRequestTimes; // General request checker 39
49 private readonly BasicDosProtectorOptions _options; 40 private readonly BasicDosProtectorOptions _options;
50 private readonly Dictionary<string, CircularBuffer<int>> _deeperInspection; // per client request checker 41 private readonly BasicDOSProtector _dosProtector;
51 private readonly Dictionary<string, int> _tempBlocked; // blocked list
52 private readonly System.Timers.Timer _forgetTimer; // Cleanup timer
53 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
54 private readonly System.Threading.ReaderWriterLockSlim _lockSlim = new System.Threading.ReaderWriterLockSlim();
55 42
56 public XmlRpcBasicDOSProtector(XmlRpcMethod normalMethod, XmlRpcMethod throttledMethod,BasicDosProtectorOptions options) 43 public XmlRpcBasicDOSProtector(XmlRpcMethod normalMethod, XmlRpcMethod throttledMethod,BasicDosProtectorOptions options)
57 { 44 {
58 _normalMethod = normalMethod; 45 _normalMethod = normalMethod;
59 _throttledMethod = throttledMethod; 46 _throttledMethod = throttledMethod;
60 _generalRequestTimes = new CircularBuffer<int>(options.MaxRequestsInTimeframe + 1,true); 47
61 _generalRequestTimes.Put(0);
62 _options = options; 48 _options = options;
63 _deeperInspection = new Dictionary<string, CircularBuffer<int>>(); 49 _dosProtector = new BasicDOSProtector(_options);
64 _tempBlocked = new Dictionary<string, int>();
65 _forgetTimer = new System.Timers.Timer();
66 _forgetTimer.Elapsed += delegate
67 {
68 _forgetTimer.Enabled = false;
69 50
70 List<string> removes = new List<string>();
71 _lockSlim.EnterReadLock();
72 foreach (string str in _tempBlocked.Keys)
73 {
74 if (
75 Util.EnvironmentTickCountSubtract(Util.EnvironmentTickCount(),
76 _tempBlocked[str]) > 0)
77 removes.Add(str);
78 }
79 _lockSlim.ExitReadLock();
80 lock (_deeperInspection)
81 {
82 _lockSlim.EnterWriteLock();
83 for (int i = 0; i < removes.Count; i++)
84 {
85 _tempBlocked.Remove(removes[i]);
86 _deeperInspection.Remove(removes[i]);
87 }
88 _lockSlim.ExitWriteLock();
89 }
90 foreach (string str in removes)
91 {
92 m_log.InfoFormat("[{0}] client: {1} is no longer blocked.",
93 _options.ReportingName, str);
94 }
95 _lockSlim.EnterReadLock();
96 if (_tempBlocked.Count > 0)
97 _forgetTimer.Enabled = true;
98 _lockSlim.ExitReadLock();
99 };
100
101 _forgetTimer.Interval = _options.ForgetTimeSpan.TotalMilliseconds;
102 } 51 }
103 public XmlRpcResponse Process(XmlRpcRequest request, IPEndPoint client) 52 public XmlRpcResponse Process(XmlRpcRequest request, IPEndPoint client)
104 { 53 {
105 // If these are set like this, this is disabled
106 if (_options.MaxRequestsInTimeframe < 1 || _options.RequestTimeSpan.TotalMilliseconds < 1)
107 return _normalMethod(request, client);
108
109 string clientstring = GetClientString(request, client);
110
111 _lockSlim.EnterReadLock();
112 if (_tempBlocked.ContainsKey(clientstring))
113 {
114 _lockSlim.ExitReadLock();
115 54
116 if (_options.ThrottledAction == ThrottleAction.DoThrottledMethod)
117 return _throttledMethod(request, client);
118 else
119 throw new System.Security.SecurityException("Throttled");
120 }
121 _lockSlim.ExitReadLock();
122
123 _generalRequestTimes.Put(Util.EnvironmentTickCount());
124
125 if (_generalRequestTimes.Size == _generalRequestTimes.Capacity &&
126 (Util.EnvironmentTickCountSubtract(Util.EnvironmentTickCount(), _generalRequestTimes.Get()) <
127 _options.RequestTimeSpan.TotalMilliseconds))
128 {
129 //Trigger deeper inspection
130 if (DeeperInspection(request, client))
131 return _normalMethod(request, client);
132 if (_options.ThrottledAction == ThrottleAction.DoThrottledMethod)
133 return _throttledMethod(request, client);
134 else
135 throw new System.Security.SecurityException("Throttled");
136 }
137 XmlRpcResponse resp = null; 55 XmlRpcResponse resp = null;
138 56 if (_dosProtector.Process(GetClientString(request, client), GetEndPoint(request, client)))
139 resp = _normalMethod(request, client); 57 resp = _normalMethod(request, client);
140 58 else
59 resp = _throttledMethod(request, client);
60
141 return resp; 61 return resp;
142 } 62 }
143 63
144 // If the service is getting more hits per expected timeframe then it starts to separate them out by client
145 private bool DeeperInspection(XmlRpcRequest request, IPEndPoint client)
146 {
147 lock (_deeperInspection)
148 {
149 string clientstring = GetClientString(request, client);
150
151
152 if (_deeperInspection.ContainsKey(clientstring))
153 {
154 _deeperInspection[clientstring].Put(Util.EnvironmentTickCount());
155 if (_deeperInspection[clientstring].Size == _deeperInspection[clientstring].Capacity &&
156 (Util.EnvironmentTickCountSubtract(Util.EnvironmentTickCount(), _deeperInspection[clientstring].Get()) <
157 _options.RequestTimeSpan.TotalMilliseconds))
158 {
159 //Looks like we're over the limit
160 _lockSlim.EnterWriteLock();
161 if (!_tempBlocked.ContainsKey(clientstring))
162 _tempBlocked.Add(clientstring, Util.EnvironmentTickCount() + (int)_options.ForgetTimeSpan.TotalMilliseconds);
163 else
164 _tempBlocked[clientstring] = Util.EnvironmentTickCount() + (int)_options.ForgetTimeSpan.TotalMilliseconds;
165 _lockSlim.ExitWriteLock();
166
167 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);
168
169 return false;
170 }
171 //else
172 // return true;
173 }
174 else
175 {
176 _deeperInspection.Add(clientstring, new CircularBuffer<int>(_options.MaxRequestsInTimeframe + 1, true));
177 _deeperInspection[clientstring].Put(Util.EnvironmentTickCount());
178 _forgetTimer.Enabled = true;
179 }
180
181 }
182 return true;
183 }
184 private string GetClientString(XmlRpcRequest request, IPEndPoint client) 64 private string GetClientString(XmlRpcRequest request, IPEndPoint client)
185 { 65 {
186 string clientstring; 66 string clientstring;
@@ -197,15 +77,12 @@ namespace OpenSim.Framework.Servers.HttpServer
197 return clientstring; 77 return clientstring;
198 } 78 }
199 79
200 } 80 private string GetEndPoint(XmlRpcRequest request, IPEndPoint client)
81 {
82 return client.Address.ToString();
83 }
201 84
202 public class BasicDosProtectorOptions
203 {
204 public int MaxRequestsInTimeframe;
205 public TimeSpan RequestTimeSpan;
206 public TimeSpan ForgetTimeSpan;
207 public bool AllowXForwardedFor;
208 public string ReportingName = "BASICDOSPROTECTOR";
209 public ThrottleAction ThrottledAction = ThrottleAction.DoThrottledMethod;
210 } 85 }
86
87
211} 88}