Skip to content
This repository was archived by the owner on Jul 9, 2023. It is now read-only.

Add support for setting up bypass rules and proxy localhost traffic #960

Open
wants to merge 1 commit into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion examples/Titanium.Web.Proxy.Examples.Wpf/MainWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,10 @@ public MainWindow()
};
proxyServer.Start();

proxyServer.SetAsSystemProxy(explicitEndPoint, ProxyProtocolType.AllHttp);
var proxyLocalhostTraffic = new SystemProxyBypassRuleSet()
.SubtractImplicitBypassRules();

proxyServer.SetAsSystemProxy(explicitEndPoint, ProxyProtocolType.AllHttp, proxyLocalhostTraffic);

InitializeComponent();
}
Expand Down
4 changes: 3 additions & 1 deletion src/Titanium.Web.Proxy/Helpers/SystemProxy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,8 @@ public SystemProxyManager()
/// <param name="hostname"></param>
/// <param name="port"></param>
/// <param name="protocolType"></param>
internal void SetProxy(string hostname, int port, ProxyProtocolType protocolType)
/// <param name="bypassRules"></param>
internal void SetProxy(string hostname, int port, ProxyProtocolType protocolType, string bypassRules)
{
using (var reg = OpenInternetSettingsKey())
{
Expand All @@ -106,6 +107,7 @@ internal void SetProxy(string hostname, int port, ProxyProtocolType protocolType
reg.SetValue(RegProxyEnable, 1);
reg.SetValue(RegProxyServer,
string.Join(";", existingSystemProxyValues.Select(x => x.ToString()).ToArray()));
reg.SetValue(RegProxyOverride, bypassRules);

Refresh();
}
Expand Down
34 changes: 33 additions & 1 deletion src/Titanium.Web.Proxy/ProxyServer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -452,6 +452,16 @@ public void SetAsSystemHttpProxy(ExplicitProxyEndPoint endPoint)
SetAsSystemProxy(endPoint, ProxyProtocolType.Http);
}

/// <summary>
/// Set the given explicit end point as the default proxy server for current machine.
/// </summary>
/// <param name="endPoint">The explicit endpoint.</param>
/// <param name="bypassRules">The system proxy bypass rules.</param>
public void SetAsSystemHttpProxy(ExplicitProxyEndPoint endPoint, SystemProxyBypassRuleSet bypassRules)
{
SetAsSystemProxy(endPoint, ProxyProtocolType.Http, bypassRules);
}

/// <summary>
/// Set the given explicit end point as the default proxy server for current machine.
/// </summary>
Expand All @@ -461,12 +471,33 @@ public void SetAsSystemHttpsProxy(ExplicitProxyEndPoint endPoint)
SetAsSystemProxy(endPoint, ProxyProtocolType.Https);
}

/// <summary>
/// Set the given explicit end point as the default proxy server for current machine.
/// </summary>
/// <param name="endPoint">The explicit endpoint.</param>
/// <param name="bypassRules">The system proxy bypass rules.</param>
public void SetAsSystemHttpsProxy(ExplicitProxyEndPoint endPoint, SystemProxyBypassRuleSet bypassRules)
{
SetAsSystemProxy(endPoint, ProxyProtocolType.Https, bypassRules);
}

/// <summary>
/// Set the given explicit end point as the default proxy server for current machine.
/// </summary>
/// <param name="endPoint">The explicit endpoint.</param>
/// <param name="protocolType">The proxy protocol type.</param>
public void SetAsSystemProxy(ExplicitProxyEndPoint endPoint, ProxyProtocolType protocolType)
{
SetAsSystemProxy(endPoint, protocolType, new SystemProxyBypassRuleSet());
}

/// <summary>
/// Set the given explicit end point as the default proxy server for current machine.
/// </summary>
/// <param name="endPoint">The explicit endpoint.</param>
/// <param name="protocolType">The proxy protocol type.</param>
/// <param name="bypassRules">The system proxy bypass rules.</param>
public void SetAsSystemProxy(ExplicitProxyEndPoint endPoint, ProxyProtocolType protocolType, SystemProxyBypassRuleSet bypassRules)
{
if (SystemProxySettingsManager == null)
throw new NotSupportedException(@"Setting system proxy settings are only supported in Windows.
Expand Down Expand Up @@ -500,7 +531,8 @@ public void SetAsSystemProxy(ExplicitProxyEndPoint endPoint, ProxyProtocolType p
? "localhost"
: endPoint.IpAddress.ToString(),
endPoint.Port,
protocolType);
protocolType,
bypassRules?.ToString() ?? string.Empty);

if (isHttp) endPoint.IsSystemHttpProxy = true;

Expand Down
72 changes: 72 additions & 0 deletions src/Titanium.Web.Proxy/SystemProxyBypassRuleSet.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
using System.Collections.Generic;
namespace Titanium.Web.Proxy;

/// <inheritdoc />
/// <summary>
/// This class is used to control when system should skip or use (in case of implicitly ignored addresses) system proxy.
/// By default for secutiry reasons proxy is ignored on local networks considered as trusted, you can disable it by using <see cref="SubtractImplicitBypassRules"/>.
/// Be aware that rules are check in order they are added, it's important when they are contradicting.
/// </summary>
public class SystemProxyBypassRuleSet
{
private const string IgnoreImplicitBypassRules = "<-loopback>";
private const string BypassSimpleHostnamesRule = "<local>";

private readonly List<string> _bypassRules;

/// <summary>
/// Initialize new system proxy rule set.
/// </summary>
public SystemProxyBypassRuleSet()
{
_bypassRules = new List<string>();
}

/// <summary>
/// Adds user defined rule to bypass system proxy.
/// </summary>
/// <param name="rule">Rule specifying which urls should not go though system proxy.</param>
/// <returns>Itself.</returns>
/// <example>
/// <code>
/// var ruleSet =
/// new SystemProxyBypassRuleSet()
/// .AddRule("https://x.*.y.com:99")
/// .AddRule("*foobar.com")
/// .AddRule("*.org:443")
/// .AddRule("192.168.1.1/16");
/// </code>
/// </example>
public SystemProxyBypassRuleSet AddRule(string rule)
{
_bypassRules.Add(rule);
return this;
}

/// <summary>
/// Adds rule for bypassing hostnames without a period in them, and that are not IP literals.
/// </summary>
/// <returns>Itself.</returns>
public SystemProxyBypassRuleSet AddSimpleHostnames()
{
_bypassRules.Add(BypassSimpleHostnamesRule);
return this;
}

/// <summary>
/// Subtracts the implicit proxy bypass rules (localhost and link local addresses).
/// This is generally only needed for test setups. Beware of the security implications to proxying localhost.
/// Ordering may matter when using a subtractive rule, as rules will be evaluated in a left-to-right order.
/// </summary>
/// <returns>Itself.</returns>
public SystemProxyBypassRuleSet SubtractImplicitBypassRules()
{
_bypassRules.Add(IgnoreImplicitBypassRules);
return this;
}

public override string ToString()
{
return string.Join(";", _bypassRules);
}
}
2 changes: 1 addition & 1 deletion src/Titanium.Web.Proxy/Titanium.Web.Proxy.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>net461;net60</TargetFrameworks>
<TargetFrameworks>net48;net60</TargetFrameworks>
<RootNamespace>Titanium.Web.Proxy</RootNamespace>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<SignAssembly>True</SignAssembly>
Expand Down
6 changes: 3 additions & 3 deletions tests/Titanium.Web.Proxy.UnitTests/SystemProxyTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,13 @@ public void CompareProxyAddressReturnedByWebProxyAndWinHttpProxyResolver()
{
CompareUrls();

proxyManager.SetProxy("127.0.0.1", 8000, ProxyProtocolType.Http);
proxyManager.SetProxy("127.0.0.1", 8000, ProxyProtocolType.Http, string.Empty);
CompareUrls();

proxyManager.SetProxy("127.0.0.1", 8000, ProxyProtocolType.Https);
proxyManager.SetProxy("127.0.0.1", 8000, ProxyProtocolType.Https, string.Empty);
CompareUrls();

proxyManager.SetProxy("127.0.0.1", 8000, ProxyProtocolType.AllHttp);
proxyManager.SetProxy("127.0.0.1", 8000, ProxyProtocolType.AllHttp, string.Empty);
CompareUrls();

// for this test you need to add a proxy.pac file to a local webserver
Expand Down