Skip to content

Support for CIDR notation in the NO_PROXY environment variable #131293

Description

@SapiensAnatis

Summary

.NET has support for reading the NO_PROXY environment variable, but does not support CIDR/subnet notation within this variable.

I happened to run into this in our work VMs which set NO_PROXY as 127.0.0.0/8 plus some other internal corporate URLs, with all outbound traffic going via a proxy. The lack of support for 127.0.0.0/8 was the root cause of an issue that caused .NET Aspire to fail to start up: all of the internal 127.0.0.1 requests it used to talk to services tried to go via our proxy, which returned an error when asked to proxy a loopback address.

Of course, you can work around this by adding 127.0.0.1 directly to the environment variable, but I thought it would be worth logging this as a potential enhancement. Other tools like curl do respect CIDR notation, as can be seen in

$ HTTPS_PROXY=https://some-proxy.com:8080 NO_PROXY=127.0.0.0/8 curl -v https://127.0.0.1

Minimal reproduction

Here is an example featuring some reflection hacks to get an instance of HttpEnvironmentProxy to demonstrate the issue:

#:property PublishAot=false

using System.Net;
using System.Reflection;

Environment.SetEnvironmentVariable("HTTP_PROXY", "http://proxy.example:8080");

var target = new Uri("http://127.0.0.1/");
Test("127.0.0.0/8", target);   // CIDR range containing 127.0.0.1
Test("127.0.0.1", target);     // exact host

void Test(string noProxy, Uri uri)
{
    Environment.SetEnvironmentVariable("NO_PROXY", noProxy);
    IWebProxy proxy = CreateEnvProxy();
    Console.WriteLine($"NO_PROXY = {noProxy,-14}  IsBypassed({uri}) = {proxy.IsBypassed(uri)}");
}

IWebProxy CreateEnvProxy()
{
    // Sorry... the type is internal, but I thought IsBypassed was the single best way to demonstrate the issue.
    Type t = typeof(HttpClient).Assembly.GetType("System.Net.Http.HttpEnvironmentProxy")!;
    MethodInfo tryCreate = t.GetMethod("TryCreate", BindingFlags.Public | BindingFlags.Static)!;
    object?[] args = { null };
    tryCreate.Invoke(null, args);
    return (IWebProxy)args[0]!;
}

The output of this program is

NO_PROXY = 127.0.0.0/8     IsBypassed(http://127.0.0.1/) = False
NO_PROXY = 127.0.0.1       IsBypassed(http://127.0.0.1/) = True

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions