diff --git a/source/Halibut/ServiceEndPoint.cs b/source/Halibut/ServiceEndPoint.cs index 7da00d51..4d160aa0 100644 --- a/source/Halibut/ServiceEndPoint.cs +++ b/source/Halibut/ServiceEndPoint.cs @@ -76,6 +76,14 @@ public ServiceEndPoint(Uri baseUri, string? remoteThumbprint, ProxyDetails? prox public ProxyDetails? Proxy { get; } + /// + /// When set, TCP connections will be made to the host and port of this URI instead of those in + /// , while the original host is still used for TLS SNI. + /// This is equivalent to curl's --resolve flag and is useful when routing through a local proxy + /// (e.g. Toxiproxy) while preserving the correct TLS handshake. + /// + public Uri? ForceResolveHost { get; set; } + public bool IsWebSocketEndpoint => IsWebSocketAddress(BaseUri); public override string ToString() => baseUriString; diff --git a/source/Halibut/Transport/TcpConnectionFactory.cs b/source/Halibut/Transport/TcpConnectionFactory.cs index 0e9c3ffd..b61e190e 100644 --- a/source/Halibut/Transport/TcpConnectionFactory.cs +++ b/source/Halibut/Transport/TcpConnectionFactory.cs @@ -79,19 +79,21 @@ await ssl.AuthenticateAsClientAsync( internal static async Task CreateConnectedTcpClientAsync(ServiceEndPoint endPoint, HalibutTimeoutsAndLimits halibutTimeoutsAndLimits, IStreamFactory streamFactory, ILog log, CancellationToken cancellationToken) { TcpClient client; + var connectHost = endPoint.ForceResolveHost?.Host ?? endPoint.BaseUri.Host; + var connectPort = endPoint.ForceResolveHost?.Port ?? endPoint.BaseUri.Port; if (endPoint.Proxy is null) { client = CreateTcpClientAsync(halibutTimeoutsAndLimits); - await client.ConnectWithTimeoutAsync(endPoint.BaseUri, endPoint.TcpClientConnectTimeout, cancellationToken); + await client.ConnectWithTimeoutAsync(connectHost, connectPort, endPoint.TcpClientConnectTimeout, cancellationToken); } else { log.Write(EventType.Diagnostic, "Creating a proxy client"); - + client = await new ProxyClientFactory(streamFactory) .CreateProxyClient(log, endPoint.Proxy) .WithTcpClientFactory(() => CreateTcpClientAsync(halibutTimeoutsAndLimits)) - .CreateConnectionAsync(endPoint.BaseUri.Host, endPoint.BaseUri.Port, endPoint.TcpClientConnectTimeout, cancellationToken); + .CreateConnectionAsync(connectHost, connectPort, endPoint.TcpClientConnectTimeout, cancellationToken); } return client; }