Recently I wanted to spy network traffic between a HttpClient
and
a REST service. This task turned out to be more difficult than I
though.
My first challenge was to force HttpClient
to use a proxy.
After a bit of googling I have found
the following code:
using System.Net;
using System.Net.Http;
var builder = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json");
var configuration = builder.Build();
var webProxy = new WebProxy(
new Uri(configuration["ProxyUri"]),
BypassOnLocal: false);
var proxyHttpClientHandler = new HttpClientHandler {
Proxy = webProxy,
UseProxy = true,
};
var httpClient = new HttpClient(proxyHttpClientHandler) {
BaseAddress = new Uri(configuration["RestServiceUri"])
};
Unfortunately my REST service was exposed on localhost
and later I found out that proxies are not used for local requests:
/* appsettings.json */
{
"RestServiceUri": "http://localhost:5001/api",
"ProxyUri": "http://localhost:8080"
}
OK, no problem I though,
let’s just add another DNS alias to localhost -
just to fool Uri
class to think
that we are accessing some other machine.
This can be done by modifying hosts
file, which
on my Ubuntu machine is located in /etc
directory:
127.0.0.1 localhost
127.0.0.2 mymachine
Then I had to change my appsettings.json
file:
/* appsettings.json */
{
"RestServiceUri": "http://mymachine:5001/api",
"ProxyUri": "http://localhost:8080"
}
And my REST service configuration so that it will listen for incoming connections on all interfaces:
public static IWebHost BuildWebHost(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.UseUrls("http://0.0.0.0:5001")
.Build();
After all these preparations I was able to intercept traffic
using ZAP Proxy:
But was this all necessary? Turns out that not really.
You may use your vanilla HttpClient
:
var restServiceUri = new Uri(configuration["RestServiceUri"]);
var httpClient = new HttpClient() {
BaseAddress = restServiceUri
};
And then just set http_proxy
environmental variable to get
exactly the same behaviour (without any need to modify hosts
, or
to force REST service to listen on all interfaces).
Just run in Bash:
http_proxy=http://localhost:8080 dotnet run
Since I don’t have any machine with Windows/MacOS I cannot confirm that it works on all OS’es, but at least it works on my Ubuntu.