/// <summary> /// Parses the handshake from the received data /// </summary> private int ParseHandshake() { int offset = 0; ushort length = BitConverter.ToUInt16(DataBuffer, 0); offset = (HandshakeHeaderLength + length); byte[] handshakeData = new ArraySegment <byte>(DataBuffer, HandshakeHeaderLength, length).ToArray(); PacketReader reader = new PacketReader(ref handshakeData, IncomingPacketType.NoHeader); ushort version = reader.ReadUInt16(); ushort subversion = Convert.ToUInt16(reader.ReadMapleString()); uint localVector = reader.ReadUInt32(); uint remoteVector = reader.ReadUInt32(); byte locale = reader.ReadInt8(); byte isLoginContext = 255; if (reader.AbsoluteLength >= 15) //Decode CRC 'n shit { isLoginContext = reader.ReadInt8(); } LocalCipher.Initialize(localVector, version); RemoteCipher.Initialize(remoteVector, version); HandshakeReceived?.Invoke(version, subversion, locale, isLoginContext); Handshaken = true; return(offset); }
private void OnMessageFramed(ReadOnlySpan <byte> message) { if (_isWaitingForHandshake) { PeerId = Encoding.ASCII.GetString(message); HandshakeReceived?.Invoke(Encoding.ASCII.GetString(message)); _isWaitingForHandshake = false; return; } MessageReceived?.Invoke(PeerId, message); }
public async Task Listen(Stream client, ResolveToServerEndpoints resolveDelegate) { // Try and read Minecraft packet structure int packetLength = await client.ReadVarInt(); // Read packet body byte[] buffer = new byte[packetLength]; await client.ReadAsync(buffer, 0, packetLength); var packetStream = new MemoryStream(buffer); int packetId = await packetStream.ReadVarInt(); if (packetId != 0) { // Not handshake packet throw new ProtocolException("Illegal packet ID for handshake"); } // Read handshake packet var handshake = await MinecraftHandshake.Read(packetStream); HandshakeReceived?.Invoke(this, handshake); // Resolve to a server endpoint based on handshake ProxyRule.ProxyEndpoint[] endpoints = resolveDelegate(handshake); if (endpoints == null || endpoints.Length == 0) { await WriteDisconnectPacket(client, $"Proxy server has no server for this hostname.", "red"); throw new NoServersMatchException(handshake); } // Try to connect to an endpoint NetworkStream tunnel = null; ProxyRule.ProxyEndpoint connectedEndpoint = null; foreach (var endpointObj in endpoints) { try { // This will just grab the endpoint, or do a DNS lookup if needed IPEndPoint endpoint = await endpointObj.GetEndpoint(); var tunnelClient = new TcpClient(); await tunnelClient.ConnectAsync(endpoint.Address, endpoint.Port); tunnel = tunnelClient.GetStream(); connectedEndpoint = endpointObj; Connected?.Invoke(this, endpointObj); break; } catch (Exception e) { EndpointFailed?.Invoke(this, endpointObj); } } if (tunnel == null || connectedEndpoint == null) { await WriteDisconnectPacket(client, $"Proxy server cannot connect to origin server.", "red"); throw new Exception("No server endpoints are accessible."); } // Modify handshake before we resend it to appear as if we connected directly to the target server bool fmlMagicStringPresent = handshake.ServerAddress.EndsWith("\0FML\0"); if (connectedEndpoint.DnsHostname == null) { handshake.ServerAddress = connectedEndpoint.Endpoint.Address.ToString(); } else { handshake.ServerAddress = connectedEndpoint.DnsHostname; } // Reappend FML magic string if (fmlMagicStringPresent) { handshake.ServerAddress += "\0FML\0"; } handshake.Port = (ushort)connectedEndpoint.Port; try { // Resend handshake packet var resendHandshakeStream = new MemoryStream(); await resendHandshakeStream.WriteVarInt(0); // Packet ID 0 (handshake) await handshake.Write(resendHandshakeStream); byte[] resendHandshakeBytes = resendHandshakeStream.ToArray(); await tunnel.WriteVarInt(resendHandshakeBytes.Length); // Packet length await tunnel.WriteAsync(resendHandshakeBytes, 0, resendHandshakeBytes.Length); // Packet body // Proxy traffic backwards and forwards await Task.WhenAny(client.CopyToAsync(tunnel), tunnel.CopyToAsync(client)); // Close connection tunnel?.Close(); client?.Close(); } catch {} }
private void HandleHandshake(string connectionId) => HandshakeReceived?.Invoke(this, connectionId);