From 7c7d2d9c247f3167cedf5dae6a00b7e4af55b034 Mon Sep 17 00:00:00 2001 From: Ian Claxton Date: Mon, 26 Sep 2022 16:28:31 +0100 Subject: [PATCH 1/3] Http Proxy Improvements Bug: proxy connect packet is malformed due to a space after HTTP/1.1. Feature: Pass the host name so proxy host acls can be matched. Feature: Switch to the WebRequest.DefaultWebProxy which allows for overriding in app.settings file and falls back to the system proxy if not configured. Improvement: Use ordinal comparision for IndexOf on the proxy response. --- QuickFIXn/SocketSettings.cs | 8 ++++++++ QuickFIXn/Transport/SocketInitiator.cs | 2 +- QuickFIXn/Transport/StreamFactory.cs | 19 ++++++++++--------- 3 files changed, 19 insertions(+), 10 deletions(-) diff --git a/QuickFIXn/SocketSettings.cs b/QuickFIXn/SocketSettings.cs index 8bb11b7eb..925dad6a0 100644 --- a/QuickFIXn/SocketSettings.cs +++ b/QuickFIXn/SocketSettings.cs @@ -14,6 +14,14 @@ public class SocketSettings : ICloneable { #region Socket Settings + /// + /// Store the socket host name so we can use it to connect via proxy if required. + /// + /// + /// The host name (without port number) to send to the proxy server for acl matching. + /// + public string SocketConnectHost { get; internal set; } + /// /// Gets a value that specifies whether the is using the Nagle algorithm. /// diff --git a/QuickFIXn/Transport/SocketInitiator.cs b/QuickFIXn/Transport/SocketInitiator.cs index bc6e061a3..d2628dfa2 100755 --- a/QuickFIXn/Transport/SocketInitiator.cs +++ b/QuickFIXn/Transport/SocketInitiator.cs @@ -173,7 +173,7 @@ private IPEndPoint GetNextSocketEndPoint(SessionID sessionID, QuickFix.Dictionar int port = System.Convert.ToInt32(settings.GetLong(portKey)); sessionToHostNum_[sessionID] = ++num; - socketSettings_.ServerCommonName = hostName; + socketSettings_.SocketConnectHost = socketSettings_.ServerCommonName = hostName; return new IPEndPoint(addrs.First(a => a.AddressFamily == AddressFamily.InterNetwork), port); } catch (System.Exception e) diff --git a/QuickFIXn/Transport/StreamFactory.cs b/QuickFIXn/Transport/StreamFactory.cs index 39a79e7b5..d7008d901 100644 --- a/QuickFIXn/Transport/StreamFactory.cs +++ b/QuickFIXn/Transport/StreamFactory.cs @@ -17,12 +17,12 @@ namespace QuickFix.Transport /// public static class StreamFactory { - private static Socket CreateTunnelThruProxy(string destIP, int destPort) + private static Socket CreateTunnelThruProxy(string destIP, int destPort, string destHostName) { string destUriWithPort = $"{destIP}:{destPort}"; UriBuilder uriBuilder = new UriBuilder(destUriWithPort); Uri destUri = uriBuilder.Uri; - IWebProxy webProxy = WebRequest.GetSystemWebProxy(); + IWebProxy webProxy = WebRequest.DefaultWebProxy; try { @@ -47,18 +47,19 @@ private static Socket CreateTunnelThruProxy(string destIP, int destPort) Socket socketThruProxy = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); socketThruProxy.Connect(proxyEndPoint); - string proxyMsg = $"CONNECT {destIP}:{destPort} HTTP/1.1 \n\n"; + string proxyMsg = !string.IsNullOrWhiteSpace(destHostName) + ? $"CONNECT {destHostName}:{destPort} HTTP/1.1\nHost: {destHostName}:{destPort}\n\n" + : $"CONNECT {destIP}:{destPort} HTTP/1.1\n\n"; byte[] buffer = Encoding.ASCII.GetBytes(proxyMsg); byte[] buffer12 = new byte[500]; socketThruProxy.Send(buffer, buffer.Length, 0); - int msg = socketThruProxy.Receive(buffer12, 500, 0); - string data; - data = Encoding.ASCII.GetString(buffer12); - int index = data.IndexOf("200"); + socketThruProxy.Receive(buffer12, 500, 0); + string data = Encoding.ASCII.GetString(buffer12); + int index = data.IndexOf("200", StringComparison.Ordinal); if (index < 0) throw new ApplicationException( - $"Connection failed to {destUriWithPort} through proxy server {proxyUri.ToString()}."); + $"Connection failed to {destUriWithPort} through proxy server {proxyUri}."); return socketThruProxy; } @@ -73,7 +74,7 @@ private static Socket CreateTunnelThruProxy(string destIP, int destPort) public static Stream CreateClientStream(IPEndPoint endpoint, SocketSettings settings, ILog logger) { // If system has configured a proxy for this config, use it. - Socket socket = CreateTunnelThruProxy(endpoint.Address.ToString(), endpoint.Port); + Socket socket = CreateTunnelThruProxy(endpoint.Address.ToString(), endpoint.Port, settings.SocketConnectHost); // No proxy. Set up a regular socket. if (socket == null) From 9241fd907e4616d5644a3c6e3dd91f385fb9ef47 Mon Sep 17 00:00:00 2001 From: Ian Claxton Date: Mon, 26 Feb 2024 13:07:55 +0000 Subject: [PATCH 2/3] As per the comment from Grant I have merged the configuration properties as requested. --- QuickFIXn/SocketSettings.cs | 8 -------- QuickFIXn/Transport/SocketInitiator.cs | 2 +- QuickFIXn/Transport/StreamFactory.cs | 2 +- 3 files changed, 2 insertions(+), 10 deletions(-) diff --git a/QuickFIXn/SocketSettings.cs b/QuickFIXn/SocketSettings.cs index fa308bc55..3915346f5 100644 --- a/QuickFIXn/SocketSettings.cs +++ b/QuickFIXn/SocketSettings.cs @@ -14,14 +14,6 @@ public class SocketSettings : ICloneable { #region Socket Settings - /// - /// Store the socket host name so we can use it to connect via proxy if required. - /// - /// - /// The host name (without port number) to send to the proxy server for acl matching. - /// - public string SocketConnectHost { get; internal set; } - /// /// Gets a value that specifies whether the is using the Nagle algorithm. /// diff --git a/QuickFIXn/Transport/SocketInitiator.cs b/QuickFIXn/Transport/SocketInitiator.cs index 1209b4ef1..f35638492 100755 --- a/QuickFIXn/Transport/SocketInitiator.cs +++ b/QuickFIXn/Transport/SocketInitiator.cs @@ -163,7 +163,7 @@ private IPEndPoint GetNextSocketEndPoint(SessionID sessionId, QuickFix.Dictionar int port = System.Convert.ToInt32(settings.GetLong(portKey)); _sessionToHostNum[sessionId] = ++num; - _socketSettings.SocketConnectHost = _socketSettings.ServerCommonName = hostName; + _socketSettings.ServerCommonName = hostName; return new IPEndPoint(addrs.First(a => a.AddressFamily == AddressFamily.InterNetwork), port); } catch (Exception e) diff --git a/QuickFIXn/Transport/StreamFactory.cs b/QuickFIXn/Transport/StreamFactory.cs index 787abf53c..d1527d5e1 100644 --- a/QuickFIXn/Transport/StreamFactory.cs +++ b/QuickFIXn/Transport/StreamFactory.cs @@ -81,7 +81,7 @@ public static Stream CreateClientStream(IPEndPoint endpoint, SocketSettings sett if (!settings.SocketIgnoreProxy) { // If system has configured a proxy for this config, use it. - socket = CreateTunnelThruProxy(endpoint.Address.ToString(), endpoint.Port, settings.SocketConnectHost); + socket = CreateTunnelThruProxy(endpoint.Address.ToString(), endpoint.Port, settings.ServerCommonName); } // No proxy. Set up a regular socket. From 69f2b21f4e62cc3b53a12a46c5e4eaaf88c8b874 Mon Sep 17 00:00:00 2001 From: Ian Claxton Date: Mon, 26 Feb 2024 13:10:55 +0000 Subject: [PATCH 3/3] As per the comment from Grant we will now assume that destHostName is always set to avoid using the ternary operator --- QuickFIXn/Transport/StreamFactory.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/QuickFIXn/Transport/StreamFactory.cs b/QuickFIXn/Transport/StreamFactory.cs index d1527d5e1..44cb0767e 100644 --- a/QuickFIXn/Transport/StreamFactory.cs +++ b/QuickFIXn/Transport/StreamFactory.cs @@ -50,9 +50,7 @@ public static class StreamFactory Socket socketThruProxy = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); socketThruProxy.Connect(proxyEndPoint); - string proxyMsg = !string.IsNullOrWhiteSpace(destHostName) - ? $"CONNECT {destHostName}:{destPort} HTTP/1.1\nHost: {destHostName}:{destPort}\n\n" - : $"CONNECT {destIp}:{destPort} HTTP/1.1\n\n"; + string proxyMsg = $"CONNECT {destHostName}:{destPort} HTTP/1.1\nHost: {destHostName}:{destPort}\n\n"; byte[] buffer = Encoding.ASCII.GetBytes(proxyMsg); byte[] buffer12 = new byte[500]; socketThruProxy.Send(buffer, buffer.Length, 0);