aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Framework/Servers/HttpServer/WebsocketServerHandler.cs
diff options
context:
space:
mode:
authorteravus2013-10-04 20:37:59 -0500
committerteravus2013-10-04 20:37:59 -0500
commit85593d8d25205344d512cbc976aa890a51f5f974 (patch)
treea81111b0deb8949386b62737a0211ffb0ee234d3 /OpenSim/Framework/Servers/HttpServer/WebsocketServerHandler.cs
parentAdded SimulatorFeatures/OpenSimExtras: say-range, whisper-range, shout-range,... (diff)
downloadopensim-SC-85593d8d25205344d512cbc976aa890a51f5f974.zip
opensim-SC-85593d8d25205344d512cbc976aa890a51f5f974.tar.gz
opensim-SC-85593d8d25205344d512cbc976aa890a51f5f974.tar.bz2
opensim-SC-85593d8d25205344d512cbc976aa890a51f5f974.tar.xz
* Add an initial complete frame timeout to the WebSocket processor to make it easier to write WebSocket service code that is resistant to Denial of Service attacks.
Diffstat (limited to 'OpenSim/Framework/Servers/HttpServer/WebsocketServerHandler.cs')
-rw-r--r--OpenSim/Framework/Servers/HttpServer/WebsocketServerHandler.cs67
1 files changed, 65 insertions, 2 deletions
diff --git a/OpenSim/Framework/Servers/HttpServer/WebsocketServerHandler.cs b/OpenSim/Framework/Servers/HttpServer/WebsocketServerHandler.cs
index de89e2e..c2925e3 100644
--- a/OpenSim/Framework/Servers/HttpServer/WebsocketServerHandler.cs
+++ b/OpenSim/Framework/Servers/HttpServer/WebsocketServerHandler.cs
@@ -28,8 +28,10 @@
28using System; 28using System;
29using System.Collections.Generic; 29using System.Collections.Generic;
30using System.IO; 30using System.IO;
31using System.Net;
31using System.Security.Cryptography; 32using System.Security.Cryptography;
32using System.Text; 33using System.Text;
34using System.Threading;
33using HttpServer; 35using HttpServer;
34 36
35namespace OpenSim.Framework.Servers.HttpServer 37namespace OpenSim.Framework.Servers.HttpServer
@@ -98,6 +100,8 @@ namespace OpenSim.Framework.Servers.HttpServer
98 /// </summary> 100 /// </summary>
99 public ValidateHandshake HandshakeValidateMethodOverride = null; 101 public ValidateHandshake HandshakeValidateMethodOverride = null;
100 102
103 private ManualResetEvent _receiveDone = new ManualResetEvent(false);
104
101 private OSHttpRequest _request; 105 private OSHttpRequest _request;
102 private HTTPNetworkContext _networkContext; 106 private HTTPNetworkContext _networkContext;
103 private IHttpClientContext _clientContext; 107 private IHttpClientContext _clientContext;
@@ -109,6 +113,8 @@ namespace OpenSim.Framework.Servers.HttpServer
109 private bool _closing; 113 private bool _closing;
110 private bool _upgraded; 114 private bool _upgraded;
111 private int _maxPayloadBytes = 41943040; 115 private int _maxPayloadBytes = 41943040;
116 private int _initialMsgTimeout = 0;
117 private int _defaultReadTimeout = 10000;
112 118
113 private const string HandshakeAcceptText = 119 private const string HandshakeAcceptText =
114 "HTTP/1.1 101 Switching Protocols\r\n" + 120 "HTTP/1.1 101 Switching Protocols\r\n" +
@@ -131,6 +137,7 @@ namespace OpenSim.Framework.Servers.HttpServer
131 { 137 {
132 _request = preq; 138 _request = preq;
133 _networkContext = pContext.GiveMeTheNetworkStreamIKnowWhatImDoing(); 139 _networkContext = pContext.GiveMeTheNetworkStreamIKnowWhatImDoing();
140 _networkContext.Stream.ReadTimeout = _defaultReadTimeout;
134 _clientContext = pContext; 141 _clientContext = pContext;
135 _bufferLength = bufferlen; 142 _bufferLength = bufferlen;
136 _buffer = new byte[_bufferLength]; 143 _buffer = new byte[_bufferLength];
@@ -206,6 +213,16 @@ namespace OpenSim.Framework.Servers.HttpServer
206 } 213 }
207 214
208 /// <summary> 215 /// <summary>
216 /// Set this to the maximum amount of milliseconds to wait for the first complete message to be sent or received on the websocket after upgrading
217 /// Default, it waits forever. Use this when your Websocket consuming code opens a connection and waits for a message from the other side to avoid a Denial of Service vector.
218 /// </summary>
219 public int InitialMsgTimeout
220 {
221 get { return _initialMsgTimeout; }
222 set { _initialMsgTimeout = value; }
223 }
224
225 /// <summary>
209 /// This triggers the websocket start the upgrade process 226 /// This triggers the websocket start the upgrade process
210 /// </summary> 227 /// </summary>
211 public void HandshakeAndUpgrade() 228 public void HandshakeAndUpgrade()
@@ -245,6 +262,7 @@ namespace OpenSim.Framework.Servers.HttpServer
245 string rawaccept = string.Format(HandshakeAcceptText, acceptKey); 262 string rawaccept = string.Format(HandshakeAcceptText, acceptKey);
246 SendUpgradeSuccess(rawaccept); 263 SendUpgradeSuccess(rawaccept);
247 264
265
248 } 266 }
249 else 267 else
250 { 268 {
@@ -258,6 +276,10 @@ namespace OpenSim.Framework.Servers.HttpServer
258 SendUpgradeSuccess(rawaccept); 276 SendUpgradeSuccess(rawaccept);
259 } 277 }
260 } 278 }
279 public IPEndPoint GetRemoteIPEndpoint()
280 {
281 return _request.RemoteIPEndPoint;
282 }
261 283
262 /// <summary> 284 /// <summary>
263 /// Generates a handshake response key string based on the client's 285 /// Generates a handshake response key string based on the client's
@@ -290,9 +312,16 @@ namespace OpenSim.Framework.Servers.HttpServer
290 WebSocketState socketState = new WebSocketState() { ReceivedBytes = new List<byte>(), Header = WebsocketFrameHeader.HeaderDefault(), FrameComplete = true}; 312 WebSocketState socketState = new WebSocketState() { ReceivedBytes = new List<byte>(), Header = WebsocketFrameHeader.HeaderDefault(), FrameComplete = true};
291 313
292 byte[] bhandshakeResponse = Encoding.UTF8.GetBytes(pHandshakeResponse); 314 byte[] bhandshakeResponse = Encoding.UTF8.GetBytes(pHandshakeResponse);
315
316
317
318
293 try 319 try
294 { 320 {
295 321 if (_initialMsgTimeout > 0)
322 {
323 _receiveDone.Reset();
324 }
296 // Begin reading the TCP stream before writing the Upgrade success message to the other side of the stream. 325 // Begin reading the TCP stream before writing the Upgrade success message to the other side of the stream.
297 _networkContext.Stream.BeginRead(_buffer, 0, _bufferLength, OnReceive, socketState); 326 _networkContext.Stream.BeginRead(_buffer, 0, _bufferLength, OnReceive, socketState);
298 327
@@ -303,6 +332,11 @@ namespace OpenSim.Framework.Servers.HttpServer
303 UpgradeCompletedDelegate d = OnUpgradeCompleted; 332 UpgradeCompletedDelegate d = OnUpgradeCompleted;
304 if (d != null) 333 if (d != null)
305 d(this, new UpgradeCompletedEventArgs()); 334 d(this, new UpgradeCompletedEventArgs());
335 if (_initialMsgTimeout > 0)
336 {
337 if (!_receiveDone.WaitOne(TimeSpan.FromMilliseconds(_initialMsgTimeout)))
338 Close(string.Empty);
339 }
306 } 340 }
307 catch (IOException) 341 catch (IOException)
308 { 342 {
@@ -489,6 +523,11 @@ namespace OpenSim.Framework.Servers.HttpServer
489 /// <param name="message">the string message that is to be sent</param> 523 /// <param name="message">the string message that is to be sent</param>
490 public void SendMessage(string message) 524 public void SendMessage(string message)
491 { 525 {
526 if (_initialMsgTimeout > 0)
527 {
528 _receiveDone.Set();
529 _initialMsgTimeout = 0;
530 }
492 byte[] messagedata = Encoding.UTF8.GetBytes(message); 531 byte[] messagedata = Encoding.UTF8.GetBytes(message);
493 WebSocketFrame textMessageFrame = new WebSocketFrame() { Header = WebsocketFrameHeader.HeaderDefault(), WebSocketPayload = messagedata }; 532 WebSocketFrame textMessageFrame = new WebSocketFrame() { Header = WebsocketFrameHeader.HeaderDefault(), WebSocketPayload = messagedata };
494 textMessageFrame.Header.Opcode = WebSocketReader.OpCode.Text; 533 textMessageFrame.Header.Opcode = WebSocketReader.OpCode.Text;
@@ -499,6 +538,11 @@ namespace OpenSim.Framework.Servers.HttpServer
499 538
500 public void SendData(byte[] data) 539 public void SendData(byte[] data)
501 { 540 {
541 if (_initialMsgTimeout > 0)
542 {
543 _receiveDone.Set();
544 _initialMsgTimeout = 0;
545 }
502 WebSocketFrame dataMessageFrame = new WebSocketFrame() { Header = WebsocketFrameHeader.HeaderDefault(), WebSocketPayload = data}; 546 WebSocketFrame dataMessageFrame = new WebSocketFrame() { Header = WebsocketFrameHeader.HeaderDefault(), WebSocketPayload = data};
503 dataMessageFrame.Header.IsEnd = true; 547 dataMessageFrame.Header.IsEnd = true;
504 dataMessageFrame.Header.Opcode = WebSocketReader.OpCode.Binary; 548 dataMessageFrame.Header.Opcode = WebSocketReader.OpCode.Binary;
@@ -531,6 +575,11 @@ namespace OpenSim.Framework.Servers.HttpServer
531 /// </summary> 575 /// </summary>
532 public void SendPingCheck() 576 public void SendPingCheck()
533 { 577 {
578 if (_initialMsgTimeout > 0)
579 {
580 _receiveDone.Set();
581 _initialMsgTimeout = 0;
582 }
534 WebSocketFrame pingFrame = new WebSocketFrame() { Header = WebsocketFrameHeader.HeaderDefault(), WebSocketPayload = new byte[0] }; 583 WebSocketFrame pingFrame = new WebSocketFrame() { Header = WebsocketFrameHeader.HeaderDefault(), WebSocketPayload = new byte[0] };
535 pingFrame.Header.Opcode = WebSocketReader.OpCode.Ping; 584 pingFrame.Header.Opcode = WebSocketReader.OpCode.Ping;
536 pingFrame.Header.IsEnd = true; 585 pingFrame.Header.IsEnd = true;
@@ -544,6 +593,11 @@ namespace OpenSim.Framework.Servers.HttpServer
544 /// <param name="message"></param> 593 /// <param name="message"></param>
545 public void Close(string message) 594 public void Close(string message)
546 { 595 {
596 if (_initialMsgTimeout > 0)
597 {
598 _receiveDone.Set();
599 _initialMsgTimeout = 0;
600 }
547 if (_networkContext == null) 601 if (_networkContext == null)
548 return; 602 return;
549 if (_networkContext.Stream != null) 603 if (_networkContext.Stream != null)
@@ -583,7 +637,11 @@ namespace OpenSim.Framework.Servers.HttpServer
583 WebSocketReader.Mask(psocketState.Header.Mask, unmask); 637 WebSocketReader.Mask(psocketState.Header.Mask, unmask);
584 psocketState.ReceivedBytes = new List<byte>(unmask); 638 psocketState.ReceivedBytes = new List<byte>(unmask);
585 } 639 }
586 640 if (psocketState.Header.Opcode != WebSocketReader.OpCode.Continue && _initialMsgTimeout > 0)
641 {
642 _receiveDone.Set();
643 _initialMsgTimeout = 0;
644 }
587 switch (psocketState.Header.Opcode) 645 switch (psocketState.Header.Opcode)
588 { 646 {
589 case WebSocketReader.OpCode.Ping: 647 case WebSocketReader.OpCode.Ping:
@@ -696,6 +754,11 @@ namespace OpenSim.Framework.Servers.HttpServer
696 } 754 }
697 public void Dispose() 755 public void Dispose()
698 { 756 {
757 if (_initialMsgTimeout > 0)
758 {
759 _receiveDone.Set();
760 _initialMsgTimeout = 0;
761 }
699 if (_networkContext != null && _networkContext.Stream != null) 762 if (_networkContext != null && _networkContext.Stream != null)
700 { 763 {
701 if (_networkContext.Stream.CanWrite) 764 if (_networkContext.Stream.CanWrite)