Skip to content

Commit

Permalink
cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
CypherPotato committed Aug 28, 2024
1 parent cf0dbed commit 8aeda49
Show file tree
Hide file tree
Showing 60 changed files with 1,167 additions and 1,112 deletions.
2 changes: 2 additions & 0 deletions extensions/Sisk.SslProxy/Constants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ static class Constants
public const string XDigestHeaderName = "X-Sisk-Proxy-Digest";
public const string XClientIpHeaderName = "X-Sisk-Proxy-Client-Ip";

public const string Server = "siskproxy/0.1";

public static readonly byte[] CHUNKED_EOF = [
0x30, // ascii 0
CH_RETURN, CH_LINEFEED,
Expand Down
5 changes: 0 additions & 5 deletions extensions/Sisk.SslProxy/DnsUtil.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,7 @@
// Repository: https://github.com/sisk-http/core

using Sisk.Core.Http;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;

namespace Sisk.Ssl;

Expand Down
2 changes: 1 addition & 1 deletion extensions/Sisk.SslProxy/HttpResponseWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public static bool TryWriteHttp1Response(Stream outgoingStream,
(string name, string value) header = headers[i];
if (string.Compare(header.name, HttpKnownHeaderNames.Server, true) == 0)
{
sw.WriteLine($"Server: Sisk/{HttpServer.SiskVersion}");
sw.WriteLine($"Server: {Constants.Server}");
}
else
{
Expand Down
38 changes: 0 additions & 38 deletions extensions/Sisk.SslProxy/SecureProxyExtensions.cs

This file was deleted.

10 changes: 7 additions & 3 deletions extensions/Sisk.SslProxy/SecureProxyForwardingResolver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@

namespace Sisk.SslProxy;

/// <summary>
/// A resolver that securely forwards the client's IP address through a trusted proxy
/// by validating the proxy's digest header.
/// </summary>
public class SecureProxyForwardingResolver : ForwardingResolver
{
/// <inheritdoc/>
Expand All @@ -21,11 +25,11 @@ public override IPAddress OnResolveClientAddress(HttpRequest request, IPEndPoint
var digestHeader = request.Headers[Constants.XDigestHeaderName];
var clientIpHeader = request.Headers[Constants.XClientIpHeaderName];

if (string.Compare(digestHeader, SecureProxy.ProxyDigest, true) == 0 && clientIpHeader is not null)
if (string.Compare(digestHeader, Ssl.SslProxy.ProxyDigest, true) == 0 && clientIpHeader is not null)
{
return IPAddress.Parse(clientIpHeader);
}
}

throw new InvalidOperationException("The incoming request ins't trusted by the proxy.");
}
}
38 changes: 0 additions & 38 deletions extensions/Sisk.SslProxy/SecureProxyServerHandler.cs

This file was deleted.

2 changes: 1 addition & 1 deletion extensions/Sisk.SslProxy/SerializerUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public static void CopyBlocking(Stream input, Stream output, EventWaitHandle wai
if (bytesRead > 0)
{
output.Write(buffer, 0, bytesRead);
input.BeginRead(buffer, 0, buffer.Length, callback, null);
input.BeginRead(buffer, 0, buffer.Length, callback, null);
}
else
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,62 +4,92 @@
// The code below is licensed under the MIT license as
// of the date of its publication, available at
//
// File name: SecureProxy.cs
// File name: SslProxy.cs
// Repository: https://github.com/sisk-http/core

using Sisk.SslProxy;
using System.Net;
using System.Net.Http;
using System.Net.Security;
using System.Net.Sockets;
using System.Security.Authentication;
using System.Security.Cryptography.X509Certificates;
using System.Text;

namespace Sisk.Ssl;

#pragma warning disable CS1591

public sealed class SecureProxy : IDisposable
/// <summary>
/// Represents a proxy server that securely forwards traffic over SSL/HTTPS.
/// </summary>
public sealed class SslProxy : IDisposable
{
public static string ProxyDigest { get; } = Guid.NewGuid().ToString();

private TcpListener listener;
private IPEndPoint remoteEndpoint;
private readonly TcpListener listener;
private readonly IPEndPoint remoteEndpoint;
private bool disposedValue;

/// <summary>
/// Gets a unique, static digest string used to verify trusted proxies.
/// </summary>
public static string ProxyDigest { get; } = Guid.NewGuid().ToString();

/// <summary>
/// Gets the SSL certificate used by the proxy server.
/// </summary>
public X509Certificate ServerCertificate { get; }

/// <summary>
/// Gets or sets a value indicating whether client certificates are required for authentication.
/// </summary>
public bool ClientCertificateRequired { get; set; } = false;

/// <summary>
/// Gets or sets the SSL/HTTPS protocols allowed for connections.
/// </summary>
public SslProtocols AllowedProtocols { get; set; } = SslProtocols.Tls12 | SslProtocols.Tls13;

/// <summary>
/// Gets or sets a value indicating whether to check for certificate revocation.
/// </summary>
public bool CheckCertificateRevocation { get; set; } = false;

/// <summary>
/// Gets or sets the timeout duration for the proxy connection.
/// </summary>
public TimeSpan ProxyTimeout { get; set; } = TimeSpan.FromSeconds(120);

public SecureProxy(int listenOn, X509Certificate certificate, IPEndPoint remoteEndpoint)
/// <summary>
/// Initializes a new instance of the <see cref="SslProxy"/> class.
/// </summary>
/// <param name="listenOn">The port number on which the proxy server listens for incoming connections.</param>
/// <param name="certificate">The SSL/TLS certificate used by the proxy server.</param>
/// <param name="remoteEndpoint">The remote endpoint to which the proxy server forwards traffic.</param>
public SslProxy(int listenOn, X509Certificate certificate, IPEndPoint remoteEndpoint)
{
this.listener = new TcpListener(IPAddress.Any, listenOn);
this.remoteEndpoint = remoteEndpoint;
ServerCertificate = certificate;
this.ServerCertificate = certificate;
}

/// <summary>
/// Starts the <see cref="SslProxy"/> and start routing traffic to the set remote endpoint.
/// </summary>
public void Start()
{
listener.Start();
listener.BeginAcceptTcpClient(ReceiveClientAsync, null);
this.listener.Start();
this.listener.BeginAcceptTcpClient(this.ReceiveClientAsync, null);

listener.Server.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.TcpKeepAliveInterval, 1);
listener.Server.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.TcpKeepAliveTime, 2);
listener.Server.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.TcpKeepAliveRetryCount, 2);
listener.Server.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true);
this.listener.Server.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.TcpKeepAliveInterval, 1);
this.listener.Server.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.TcpKeepAliveTime, 2);
this.listener.Server.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.TcpKeepAliveRetryCount, 2);
this.listener.Server.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true);
}

void ReceiveClientAsync(IAsyncResult ar)
{
listener.BeginAcceptTcpClient(ReceiveClientAsync, null);
var client = listener.EndAcceptTcpClient(ar);
this.listener.BeginAcceptTcpClient(this.ReceiveClientAsync, null);
var client = this.listener.EndAcceptTcpClient(ar);

client.NoDelay = true;

if (disposedValue)
if (this.disposedValue)
return;

using (var tcpStream = client.GetStream())
Expand All @@ -68,9 +98,9 @@ void ReceiveClientAsync(IAsyncResult ar)
{
try
{
httpClient.Connect(remoteEndpoint);
httpClient.SendTimeout = (int)(ProxyTimeout.TotalSeconds);
httpClient.ReceiveTimeout = (int)(ProxyTimeout.TotalSeconds);
httpClient.Connect(this.remoteEndpoint);
httpClient.SendTimeout = (int)(this.ProxyTimeout.TotalSeconds);
httpClient.ReceiveTimeout = (int)(this.ProxyTimeout.TotalSeconds);
}
catch
{
Expand All @@ -83,18 +113,23 @@ void ReceiveClientAsync(IAsyncResult ar)
{
try
{
sslStream.AuthenticateAsServer(ServerCertificate, ClientCertificateRequired, AllowedProtocols, CheckCertificateRevocation);
sslStream.AuthenticateAsServer(this.ServerCertificate, this.ClientCertificateRequired, this.AllowedProtocols, this.CheckCertificateRevocation);
}
catch (Exception)
{
return;
}

while (client.Connected && !disposedValue)
while (client.Connected && !this.disposedValue)
{
try
{
if (!HttpRequestReader.TryReadHttp1Request(sslStream, out var method, out var path, out var proto, out var reqContentLength, out var headers))
if (!HttpRequestReader.TryReadHttp1Request(sslStream,
out var method,
out var path,
out var proto,
out var reqContentLength,
out var headers))
{
return;
}
Expand Down Expand Up @@ -178,22 +213,23 @@ void ReceiveClientAsync(IAsyncResult ar)

private void Dispose(bool disposing)
{
if (!disposedValue)
if (!this.disposedValue)
{
if (disposing)
{
listener.Stop();
listener.Dispose();
this.listener.Stop();
this.listener.Dispose();
}

disposedValue = true;
this.disposedValue = true;
}
}

/// <inheritdoc/>
public void Dispose()
{
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
Dispose(disposing: true);
this.Dispose(disposing: true);
GC.SuppressFinalize(this);
}
}
46 changes: 46 additions & 0 deletions extensions/Sisk.SslProxy/SslProxyExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// The Sisk Framework source code
// Copyright (c) 2023 PROJECT PRINCIPIUM
//
// The code below is licensed under the MIT license as
// of the date of its publication, available at
//
// File name: SslProxyExtensions.cs
// Repository: https://github.com/sisk-http/core

using Sisk.Core.Http.Hosting;
using System.Security.Authentication;
using System.Security.Cryptography.X509Certificates;

namespace Sisk.Ssl;

/// <summary>
/// Provides extension methods for <see cref="SslProxy"/>.
/// </summary>
public static class SslProxyExtensions
{
/// <summary>
/// Configures the <see cref="HttpServerHostContext"/> to use <see cref="SslProxy"/> with the specified parameters.
/// </summary>
/// <param name="builder">The <see cref="HttpServerHostContextBuilder"/> instance to configure.</param>
/// <param name="sslListeningPort">The port number on which the server will listen for SSL/HTTPS connections.</param>
/// <param name="certificate">The SSL/HTTPS certificate to use for encrypting communications.</param>
/// <param name="allowedProtocols">The SSL/HTTPS protocols allowed for the connection. Defaults to <see cref="SslProtocols.Tls12"/> and <see cref="SslProtocols.Tls13"/>.</param>
/// <param name="clientCertificateRequired">Specifies whether a client certificate is required for authentication. Defaults to <c>false</c>.</param>
/// <returns>The configured <see cref="HttpServerHostContextBuilder"/> instance.</returns>
public static HttpServerHostContextBuilder UseSsl(
this HttpServerHostContextBuilder builder,
short sslListeningPort,
X509Certificate certificate,
SslProtocols allowedProtocols = SslProtocols.Tls12 | SslProtocols.Tls13,
bool clientCertificateRequired = false)
{
var endpoint = DnsUtil.ResolveEndpoint(builder.ServerConfiguration.ListeningHosts[0].Ports[0]);
var secureProxy = new SslProxy(sslListeningPort, certificate, endpoint);
var serverHandler = new SslProxyServerHandler(secureProxy);

builder.UseHandler(serverHandler);
builder.UseStartupMessage($"The SSL proxy is listening at:\n- https://localhost:{sslListeningPort}/");

return builder;
}
}
Loading

0 comments on commit 8aeda49

Please sign in to comment.