Example #1
0
        private bool ShakeHandsHixie76()
        {
            // Ensure we have all the data we need
            if ((_Header.ContainsKey("Key1")) && (_Header.ContainsKey("Key2")) && (_Header.ContainsKey("Host")) && (_Header.ContainsKey("Origin")) && (_Header.ContainsKey("Path")))
            {
                List <byte> ToHash = new List <byte>();
                byte[]      TempBytes;

                // Get the data to hash
                TempBytes = BitConverter.GetBytes(CalculateWebSocketKey(_Header["Key1"]));
                for (int i = 3; i >= 0; i--)
                {
                    ToHash.Add(TempBytes[i]);
                }
                TempBytes = BitConverter.GetBytes(CalculateWebSocketKey(_Header["Key2"]));
                for (int i = 3; i >= 0; i--)
                {
                    ToHash.Add(TempBytes[i]);
                }
                ToHash.AddRange(ReadBytes(8));

                // Hash the data
                byte[] Hashed = MD5.Create().ComputeHash(ToHash.ToArray());

                // Setup the handshake response
                string Response = "HTTP/1.1 101 Web Socket Protocol Handshake\r\n" +
                                  "Upgrade: WebSocket\r\n" +
                                  "Connection: Upgrade\r\n" +
                                  "Sec-WebSocket-Origin: " + _Header["Origin"] + "\r\n" +
                                  "Sec-WebSocket-Location: ws://" + _Header["Host"] + _Header["Path"] + "\r\n";
                if (_Header.ContainsKey("SubProtocol"))
                {
                    Response += "Sec-WebSocket-Protocol: plain\r\n";                                     // Only sub-protocol we support
                }
                Response += "\r\n";

                // Send the response and return
                WriteBytes(Encoding.ASCII.GetBytes(Response));
                WriteBytes(Hashed);

                return(true);
            }
            else
            {
                // We're missing some pice of data, log what we do have
                RMLog.Error("Missing some piece of handshake data.  Here's what we have:");
                foreach (DictionaryEntry DE in _Header)
                {
                    RMLog.Error(DE.Key + " => " + DE.Value);
                }
                return(false);
            }
        }
Example #2
0
        private bool ShakeHandsRFC6455()
        {
            // Ensure we have all the data we need
            // TODOX Firefox (v49, maybe others) is not sending an Origin header, which breaks things
            // TODOX if ((_Header.ContainsKey("Key")) && (_Header.ContainsKey("Host")) && (_Header.ContainsKey("Origin")) && (_Header.ContainsKey("Path")))
            if ((_Header.ContainsKey("Key")) && (_Header.ContainsKey("Host")) && (_Header.ContainsKey("Path")))
            {
                string AcceptGUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";

                // Combine Key and GUID
                string ToHash = _Header["Key"] + AcceptGUID;

                // Hash the string
                byte[] Hashed = SHA1.Create().ComputeHash(Encoding.ASCII.GetBytes(ToHash));

                // Encode the hash
                string Encoded = Convert.ToBase64String(Hashed);

                // Setup the handshake response
                var Response = "HTTP/1.1 101 Switching Protocols\r\n" +
                               "Upgrade: websocket\r\n" +
                               "Connection: Upgrade\r\n" +
                               "Sec-WebSocket-Accept: " + Encoded + "\r\n";
                if (_Header.ContainsKey("SubProtocol"))
                {
                    Response += "Sec-WebSocket-Protocol: plain\r\n";                                     // Only sub-protocol we support
                }
                Response += "\r\n";

                // Send the response and return
                WriteBytes(Encoding.ASCII.GetBytes(Response));

                return(true);
            }
            else
            {
                // We're missing some pice of data, log what we do have
                RMLog.Error("Missing some piece of handshake data.  Here's what we have:");
                foreach (DictionaryEntry DE in _Header)
                {
                    RMLog.Error(DE.Key + " => " + DE.Value);
                }
                return(false);
            }
        }
Example #3
0
        private bool ShakeHands()
        {
            _Header["Version"] = "0";

            try
            {
                // Peek first byte for 22, 128 (indicates ssl)
                // Don't use class methods for peek/read since they eat data into the input buffer, and AuthenticateAsServer needs that data
                if (_Socket.Poll(5 * 1000 * 1000, SelectMode.SelectRead))
                {
                    byte[] FirstByte = new byte[1];
                    _Socket.Receive(FirstByte, 0, 1, SocketFlags.Peek);
                    if ((FirstByte[0] == 22) || (FirstByte[0] == 128))
                    {
                        if (_Certificate == null)
                        {
                            throw new Exception("wss:// requires a certificate");
                        }
                        else
                        {
                            var SSL = new SslStream(_Stream, false);
                            _Stream = SSL;
                            SSL.AuthenticateAsServer(_Certificate, false, SslProtocols.Tls, false);
                            Protocol = "wss";
                        }
                    }
                }
                else
                {
                    RMLog.Error("Timeout exceeded while waiting for complete handshake");
                    return(false);
                }

                // Keep reading header data until we get all the data we want
                while (true)
                {
                    // Read another line, and abort if we don't get one within 5 seconds
                    string InLine = ReadLn(new string[] { "\r\n", "\0" }, false, '\0', 5000).Trim();
                    if (ReadTimedOut)
                    {
                        RMLog.Error("Timeout exceeded while waiting for complete handshake");
                        return(false);
                    }

                    RMLog.Trace("Handshake Line: " + InLine);

                    // Check for blank line (indicates we have most of the header, and only the last 8 bytes remain
                    if (string.IsNullOrEmpty(InLine))
                    {
                        switch (_Header["Version"])
                        {
                        case "0":
                            if (_Header.ContainsKey("Sec-WebSocket-Key1"))
                            {
                                _ProtocolVersion = ProtocolVersion.Hixie76;
                                return(ShakeHandsHixie76());
                            }
                            else
                            {
                                // Only used by Chrome 4 and iOS 5.0.0 so probably not worth bothering
                                _ProtocolVersion = ProtocolVersion.Hixie75;
                                return(false);
                            }

                        case "7":
                        case "8":
                        case "13":
                            _ProtocolVersion = ProtocolVersion.RFC6455;
                            return(ShakeHandsRFC6455());

                        default:
                            //		    TODO If this version does not
                            //          match a version understood by the server, the server MUST
                            //          abort the websocket handshake described in this section and
                            //          instead send an appropriate HTTP error code (such as 426
                            //          Upgrade Required), and a |Sec-WebSocket-Version| header
                            //          indicating the version(s) the server is capable of
                            //          understanding.
                            return(false);
                        }
                        break;
                    }
                    else if (InLine.StartsWith("Connection:"))
                    {
                        // Example: "Connection: Upgrade"
                        // NB: New in protocol 8+
                        _Header["Connection"] = InLine.Replace("Connection:", "").Trim();
                    }
                    else if (InLine.StartsWith("GET"))
                    {
                        // Example: "GET /demo HTTP/1.1"
                        string[] GET = InLine.Split(' ');
                        _Header["Path"] = GET[1];
                    }
                    else if (InLine.StartsWith("Host:"))
                    {
                        // Example: "Host: example.com"
                        _Header["Host"] = InLine.Replace("Host:", "").Trim();
                    }
                    else if (InLine.StartsWith("Origin:"))
                    {
                        // Example: "Origin: http://example.com"
                        // NB: Not used in protocol 8+
                        _Header["Origin"] = InLine.Replace("Origin:", "").Trim();
                    }
                    else if (InLine.StartsWith("Sec-WebSocket-Key:"))
                    {
                        // Example: "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ=="
                        // NB: New in protocol 8+
                        _Header["Key"] = InLine.Replace("Sec-WebSocket-Key:", "").Trim();
                    }
                    else if (InLine.StartsWith("Sec-WebSocket-Key1:"))
                    {
                        // Example: "Sec-WebSocket-Key1: 4 @1  46546xW%0l 1 5"
                        // NB: Not used in protocol 8+
                        _Header["Key1"] = InLine.Replace("Sec-WebSocket-Key1:", "").Trim();
                    }
                    else if (InLine.StartsWith("Sec-WebSocket-Key2:"))
                    {
                        // Example: "Sec-WebSocket-Key2: 12998 5 Y3 1  .P00"
                        // NB: Not used in protocol 8+
                        _Header["Key2"] = InLine.Replace("Sec-WebSocket-Key2:", "").Trim();
                    }
                    else if (InLine.StartsWith("Sec-WebSocket-Origin:"))
                    {
                        // Example: "Sec-WebSocket-Origin: http://example.com"
                        // NB: New in protocol 8+
                        _Header["Origin"] = InLine.Replace("Sec-WebSocket-Origin:", "").Trim();
                    }
                    else if (InLine.StartsWith("Sec-WebSocket-Protocol:"))
                    {
                        // Example: "Sec-WebSocket-Protocol: sample"
                        _Header["SubProtocol"] = InLine.Replace("Sec-WebSocket-Protocol:", "").Trim();
                    }
                    else if (InLine.StartsWith("Sec-WebSocket-Draft"))
                    {
                        // Example: "Sec-WebSocket-Draft: 2"
                        _Header["Version"] = InLine.Replace("Sec-WebSocket-Draft:", "").Trim();
                    }
                    else if (InLine.StartsWith("Sec-WebSocket-Version"))
                    {
                        // Example: "Sec-WebSocket-Version: 8"
                        _Header["Version"] = InLine.Replace("Sec-WebSocket-Version:", "").Trim();
                    }
                    else if (InLine.StartsWith("Upgrade:"))
                    {
                        // Example: "Upgrade: websocket"
                        // NB: New in protocol 8+
                        _Header["Upgrade"] = InLine.Replace("Upgrade:", "").Trim();
                    }
                    else if (InLine.StartsWith("<policy-file-request"))
                    {
                        string PolicyResponse =
                            "<?xml version=\"1.0\"?>\n" +
                            "<cross-domain-policy>\n" +
                            "   <allow-access-from domain=\"*\" to-ports=\"*\"/>\n" +
                            "   <site-control permitted-cross-domain-policies=\"all\"/>\n" +
                            "</cross-domain-policy>\n" +
                            "\0";
                        WriteRaw(Encoding.UTF8.GetBytes(PolicyResponse));
                        FlashPolicyFileRequest = true;
                        return(false);
                    }
                }
            }
            catch (Exception ex)
            {
                RMLog.Exception(ex, "Exception in WebSocketConnection::ShakeHands()");
            }

            return(false);
        }
Example #4
0
        public bool Open(int ASocketHandle)
        {
            if (OSUtils.IsWindows)
            {
                try
                {
                    NativeMethods.WSAData WSA    = new NativeMethods.WSAData();
                    SocketError           Result = NativeMethods.WSAStartup((short)0x0202, out WSA);
                    if (Result != SocketError.Success)
                    {
                        throw new SocketException(NativeMethods.WSAGetLastError());
                    }

                    SocketPermission SP = new SocketPermission(System.Security.Permissions.PermissionState.Unrestricted);
                    SP.Demand();

                    SocketInformation SI = new SocketInformation();
                    SI.Options             = SocketInformationOptions.Connected;
                    SI.ProtocolInformation = new byte[Marshal.SizeOf(typeof(NativeMethods.WSAPROTOCOL_INFO))];

                    Result = SocketError.Success;
                    unsafe
                    {
                        fixed(byte *pinnedBuffer = SI.ProtocolInformation)
                        {
                            Result = NativeMethods.WSADuplicateSocket(new IntPtr(ASocketHandle), (uint)Process.GetCurrentProcess().Id, pinnedBuffer);
                        }
                    }

                    if (Result != SocketError.Success)
                    {
                        throw new SocketException(NativeMethods.WSAGetLastError());
                    }

                    return(Open(new Socket(SI)));
                }
                catch (SocketException sex)
                {
                    RMLog.Exception(sex, "SocketException in TcpConnection::Open().  ErrorCode=" + sex.ErrorCode.ToString());
                    return(false);
                }
                catch (Exception ex)
                {
                    RMLog.Exception(ex, "Exception in TcpConnection::Open()");
                    return(false);
                }
            }
            else
            {
                RMLog.Error("MONO cannot open an existing socket handle");
                return(false);
                //try
                //{
                //    SocketInformation SI = new SocketInformation();
                //    SI.Options = SocketInformationOptions.Connected;
                //    SI.ProtocolInformation = new byte[24];

                //    // From Mono's Socket.cs DuplicateAndClose() SI.ProtocolInformation = Mono.DataConverter.Pack("iiiil", (int)address_family, (int)socket_type, (int)protocol_type, isbound ? 1 : 0, (long)socket);
                //    byte[] B1 = BitConverter.GetBytes((int)AddressFamily.InterNetwork);
                //    byte[] B2 = BitConverter.GetBytes((int)SocketType.Stream);
                //    byte[] B3 = BitConverter.GetBytes((int)ProtocolType.Tcp);
                //    byte[] B4 = BitConverter.GetBytes((int)1);
                //    byte[] B5 = BitConverter.GetBytes((long)ASocketHandle);
                //    Array.Copy(B1, 0, SI.ProtocolInformation, 0, B1.Length);
                //    Array.Copy(B2, 0, SI.ProtocolInformation, 4, B2.Length);
                //    Array.Copy(B3, 0, SI.ProtocolInformation, 8, B3.Length);
                //    Array.Copy(B4, 0, SI.ProtocolInformation, 12, B4.Length);
                //    Array.Copy(B5, 0, SI.ProtocolInformation, 16, B5.Length);

                //    return Open(new Socket(SI));
                //}
                //catch (SocketException sex)
                //{
                //    RMLog.Exception(sex, "SocketException in TcpConnection::Open().  ErrorCode=" + sex.ErrorCode.ToString());
                //    return false;
                //}
                //catch (Exception ex)
                //{
                //    RMLog.Exception(ex, "Exception in TcpConnection::Open()");
                //    return false;
                //}
            }
        }