1
0
mirror of https://github.com/Ylianst/MeshCommander synced 2025-12-06 06:03:20 +00:00
Files
MeshCommander/webrelay.ashx
Ylian Saint-Hilaire 3deafe34ef first commit
2020-03-09 11:11:06 -07:00

175 lines
6.3 KiB
Plaintext

<%@ WebHandler Language="C#" Class="ManageabilityCommander.WebRelay" %>
using System;
using System.IO;
using System.Net;
using System.Web;
using System.Linq;
using System.Text;
using System.Threading;
using System.Collections;
using System.Net.Sockets;
using System.Net.Security;
using System.Web.WebSockets;
using System.Net.WebSockets;
using System.Threading.Tasks;
using System.Collections.Generic;
using System.Security.Cryptography;
using System.Security.Authentication;
using System.Security.Cryptography.X509Certificates;
namespace ManageabilityCommander
{
/// <summary>
/// WebSocket to TCP/TLS bridge. This handler accepts a websocket connection and forwards the traffic to TCP/TLS.
/// </summary>
public class WebRelay : IHttpHandler
{
string host = null;
int port = 0;
bool tls = false;
WebSocket websocket = null;
TcpClient client = null;
Stream stream = null;
byte[] clientReadBuf = new byte[16384];
bool closing = false;
object mainlock = new object();
public bool IsReusable { get { return false; } }
private void Log(string x) { lock (mainlock) { File.AppendAllText("C:\\temp\\tlog.txt", DateTime.Now.ToString() + " - " + x.Replace('\0', '~') + "\r\n"); } }
public void ProcessRequest(HttpContext context)
{
var queryargs = System.Web.HttpUtility.ParseQueryString(context.Request.Url.Query);
if (!context.IsWebSocketRequest)
{
context.Response.StatusCode = 200;
context.Response.Redirect("default.htm");
context.Response.End();
return;
}
if (queryargs["host"] == null || queryargs["port"] == null || queryargs["tls"] == null)
{
context.Response.StatusCode = 200;
context.Response.ContentType = "text/plain";
context.Response.Write("Host, Port and Tls arguments expected.");
context.Response.End();
return;
}
host = queryargs["host"];
int.TryParse(queryargs["port"], out port);
tls = (queryargs["tls"] != null && string.Compare(queryargs["tls"], "1", true) == 0);
if (port < 1 || port > 65535)
{
context.Response.StatusCode = 200;
context.Response.ContentType = "text/plain";
context.Response.Write("Invalid port.");
context.Response.End();
return;
}
try
{
context.AcceptWebSocketRequest(ProcessNewWebSocket);
}
catch (Exception ex)
{
context.Response.StatusCode = 202;
context.Response.ContentType = "text/plain";
context.Response.Write("AcceptWebSocketRequest() Error: " + ex.ToString());
context.Response.End();
}
}
private bool CheckClientCert(object sender, X509Certificate cert, X509Chain chain, SslPolicyErrors errors)
{
return true;
}
private async Task ProcessNewWebSocket(AspNetWebSocketContext context)
{
websocket = context.WebSocket;
client = new TcpClient();
try { await client.ConnectAsync(host, port); } catch (Exception) { client = null; }
if (client == null)
{
await websocket.CloseAsync(WebSocketCloseStatus.EndpointUnavailable, "Unable to TCP connect to target host:port", CancellationToken.None);
websocket.Dispose();
websocket = null;
return;
}
try
{
if (tls == false)
{
stream = client.GetStream();
stream.BeginRead(clientReadBuf, 0, clientReadBuf.Length, new AsyncCallback(onClientReadData), null);
}
else
{
SslStream secureClientStream = new SslStream(client.GetStream(), false, new RemoteCertificateValidationCallback(CheckClientCert), null, EncryptionPolicy.RequireEncryption);
stream = secureClientStream;
secureClientStream.AuthenticateAsClientAsync(host).Wait();
stream.BeginRead(clientReadBuf, 0, clientReadBuf.Length, new AsyncCallback(onClientReadData), null);
}
}
catch (Exception) { closing = true; }
while (closing == false)
{
try
{
ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[16384]);
WebSocketReceiveResult result = await websocket.ReceiveAsync(buffer, CancellationToken.None);
if (closing == true || websocket.State != WebSocketState.Open) break;
stream.WriteAsync(buffer.Array, buffer.Offset, result.Count).Wait();
}
catch (Exception) { }
}
try
{
await websocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Remote TCP connection closed", CancellationToken.None);
websocket.Dispose();
}
catch (Exception) { }
websocket = null;
stream = null;
try { client.Close(); } catch (Exception) { }
client = null;
}
private void onClientReadData(IAsyncResult ar)
{
int r = 0;
try { r = stream.EndRead(ar); } catch (Exception) { }
try
{
if (r == 0)
{
closing = true;
try { websocket.Abort(); } catch (Exception) { }
}
else
{
websocket.SendAsync(new ArraySegment<byte>(clientReadBuf, 0, r), WebSocketMessageType.Binary, true, CancellationToken.None).Wait();
stream.BeginRead(clientReadBuf, 0, clientReadBuf.Length, new AsyncCallback(onClientReadData), null);
}
}
catch (Exception) {
closing = true;
try { websocket.Abort(); } catch (Exception) { }
}
}
}
}