Eavesdrop 2.0.0-alpha.38
dotnet add package Eavesdrop --version 2.0.0-alpha.38
NuGet\Install-Package Eavesdrop -Version 2.0.0-alpha.38
<PackageReference Include="Eavesdrop" Version="2.0.0-alpha.38" />
<PackageVersion Include="Eavesdrop" Version="2.0.0-alpha.38" />
<PackageReference Include="Eavesdrop" />
paket add Eavesdrop --version 2.0.0-alpha.38
#r "nuget: Eavesdrop, 2.0.0-alpha.38"
#:package Eavesdrop@2.0.0-alpha.38
#addin nuget:?package=Eavesdrop&version=2.0.0-alpha.38&prerelease
#tool nuget:?package=Eavesdrop&version=2.0.0-alpha.38&prerelease
Eavesdrop
A programmable HTTP(S) interception proxy for .NET.
Eavesdrop is a machine-local proxy that can inspect, modify, block, or forward HTTP and HTTPS traffic. It configures the system to use a PAC file served by the local proxy, can generate certificates for HTTPS interception, and exposes asynchronous request and response hooks so applications can participate directly in the interception pipeline.
Although the package multi-targets modern .NET and .NET Standard, the current design is centered around Windows system proxy behavior. HTTPS certificate generation also has platform-specific behavior that is more mature on Windows than on Linux.
What It Does
- Intercepts outbound HTTP and HTTPS traffic from the local machine
- Lets you inspect and mutate
HttpRequestMessageandHttpResponseMessageinstances - Supports host-based allowlists and blocklists through PAC rules
- Can bypass intranet and private-network traffic, or include it explicitly
- Can forward traffic to another proxy instead of terminating TLS locally
- Streams chunked HTTP/1.1 responses without buffering the full payload
Quick Start
Install the package:
dotnet add package Eavesdrop
Minimal setup:
using Eavesdrop;
Eavesdropper.CertProvider.TryCreateTrustedRootCA("Eavesdrop");
Eavesdropper.RequestInterceptedAsync += async (_, e) =>
{
Console.WriteLine($"{e.Method} {e.Uri}");
await Task.CompletedTask;
};
Eavesdropper.ResponseInterceptedAsync += async (_, e) =>
{
Console.WriteLine($"{(int)e.StatusCode} {e.Uri}");
await Task.CompletedTask;
};
Eavesdropper.Initiate(12030);
Console.WriteLine("Press any key to stop...");
Console.ReadKey();
Eavesdropper.Terminate();
How It Works
When Eavesdropper.Initiate(port) is called, Eavesdrop:
- Starts a local socket listener on the specified port.
- Serves a PAC file from
http://127.0.0.1:{port}/proxy_{port}.pac/. - Updates the machine's proxy configuration so traffic is routed through that PAC file.
- Accepts HTTP requests directly, and handles HTTPS by processing the
CONNECTtunnel and optionally terminating TLS locally.
If HTTPS interception is enabled, the library generates per-host certificates from a trusted root certificate authority. That root CA must exist before HTTPS traffic can be decrypted.
When Terminate() is called, Eavesdrop removes the saved proxy settings, stops accepting new connections, and cancels pending outbound requests.
Important Notes
- This library changes machine-level proxy behavior while it is running.
- HTTPS interception requires trusting a locally generated root certificate.
- If you do not create a trusted root CA, HTTPS interception will fail when the proxy attempts to process
CONNECTrequests. Eavesdropperis a static, process-wide API. Configuration is global for the current process.- The default upstream
HttpClientdoes not automatically redirect responses.
Configuration
Certificate Authority
HTTPS interception depends on Eavesdropper.CertProvider, which caches issued certificates and creates host certificates from a root CA.
The simplest setup is:
bool success = Eavesdropper.CertProvider.TryCreateTrustedRootCA("Eavesdrop");
This overload creates a certificate authority with:
- Organization:
Eavesdrop - Common name:
Eavesdrop Root Certificate Authority
You can also specify both values explicitly:
bool success = Eavesdropper.CertProvider.TryCreateTrustedRootCA(
organization: "My Company",
commonName: "My Company Development Root CA");
The certificate provider also exposes:
NotBeforeandNotAfterto control issued certificate validityIsRootCATrustedto indicate whether the root CA was successfully added to the user root storeRootCertificateAuthorityfor access to the loaded or generated CA certificate
Host Filtering
Host filtering is controlled by two members:
Eavesdropper.TargetsEavesdropper.IsProxyingTargets
Behavior:
- When
IsProxyingTargets == false, entries inTargetsare excluded from interception. - When
IsProxyingTargets == true, only entries inTargetsare intercepted.
Exclude all google.com traffic:
Eavesdropper.Targets.Add("*google.com");
Intercept only GitHub and Microsoft:
Eavesdropper.IsProxyingTargets = true;
Eavesdropper.Targets.Add("*github.com");
Eavesdropper.Targets.Add("*microsoft.com");
Use wildcard prefixes such as *github.com instead of *.github.com so both the root domain and subdomains are matched by the PAC file.
Private Networks and Intranet Hosts
By default, the generated PAC file bypasses:
- Plain host names
*.local10.*172.16.*192.168.*
To include private networks in interception:
Eavesdropper.IsProxyingPrivateNetworks = true;
If you use internal DNS names for intranet services, add them explicitly:
Eavesdropper.IntranetHosts.Add("portainer.nginx.svc");
Eavesdropper.IntranetHosts.Add("sonarr.nginx.svc");
HTTP-Only Interception
If you only want to intercept HTTP traffic and leave HTTPS direct:
Eavesdropper.IsOnlyInterceptingHttp = true;
This injects PAC behavior that returns DIRECT for HTTPS URLs.
Custom PAC Logic
You can prepend custom JavaScript to the PAC file through Eavesdropper.PACHeader:
Eavesdropper.PACHeader = """
if (dnsDomainIs(host, "example.internal"))
return "DIRECT";
""";
This is useful when you need PAC rules that go beyond Targets, IntranetHosts, or IsOnlyInterceptingHttp.
Forwarding to an Upstream Proxy
You can route intercepted traffic to another proxy:
var upstreamProxy = new WebProxy("http://10.10.10.10:80")
{
Credentials = CredentialCache.DefaultNetworkCredentials
};
Eavesdropper.Proxy = upstreamProxy;
If you want Eavesdrop to behave as a forwarding proxy instead of decrypting HTTPS locally:
Eavesdropper.Proxy = new WebProxy("http://10.10.10.10:80");
Eavesdropper.IsActingAsForwardingServer = true;
IsActingAsForwardingServer requires Proxy to be configured first. Otherwise, the property setter throws.
Interception Pipeline
Eavesdrop exposes two async events:
Eavesdropper.RequestInterceptedAsyncEavesdropper.ResponseInterceptedAsync
Each event is awaited by the proxy pipeline, so handlers can perform asynchronous work before traffic continues.
Inspecting Requests
RequestInterceptedEventArgs exposes:
RequestMethodContentHeadersUriVersionResponseIsInterceptingResponseCancel
Example:
Eavesdropper.RequestInterceptedAsync += async (_, e) =>
{
Console.WriteLine($"{e.Method} {e.Uri}");
foreach ((string name, IEnumerable<string> values) in e.Headers)
{
Console.WriteLine($"{name}: {string.Join(", ", values)}");
}
await Task.CompletedTask;
};
Modifying Requests
You can mutate the request in place:
Eavesdropper.RequestInterceptedAsync += async (_, e) =>
{
e.Headers.Remove("X-Debug");
e.Headers.TryAddWithoutValidation("X-Debug", "intercepted");
if (e.Content != null)
{
string body = await e.Content.ReadAsStringAsync().ConfigureAwait(false);
e.Content = new StringContent(body.Replace("before", "after"));
}
};
You can also replace the entire request:
Eavesdropper.RequestInterceptedAsync += (_, e) =>
{
e.Request = new HttpRequestMessage(HttpMethod.Get, "https://example.com/replacement");
return Task.CompletedTask;
};
Short-Circuiting with a Custom Response
If you assign e.Response during request interception, Eavesdrop skips the outbound request and returns your response directly:
Eavesdropper.RequestInterceptedAsync += (_, e) =>
{
if (e.Uri?.Host == "example.com")
{
e.Response = new HttpResponseMessage(HttpStatusCode.Forbidden)
{
Content = new StringContent("Blocked by Eavesdrop")
};
}
return Task.CompletedTask;
};
Skipping Response Interception
If you only need request-time handling, you can disable the response hook for that request:
Eavesdropper.RequestInterceptedAsync += (_, e) =>
{
e.IsInterceptingResponse = false;
return Task.CompletedTask;
};
Inspecting and Modifying Responses
ResponseInterceptedEventArgs exposes:
ResponseRequestUriStatusCodeReasonPhraseVersionHeadersContentIsSuccessStatusCodeCancel
Example:
Eavesdropper.ResponseInterceptedAsync += async (_, e) =>
{
Console.WriteLine($"{(int)e.StatusCode} {e.Uri}");
if (e.Content != null)
{
string body = await e.Content.ReadAsStringAsync().ConfigureAwait(false);
e.Content = new StringContent(body.Replace("server", "proxy"));
}
};
You can also replace the whole response:
Eavesdropper.ResponseInterceptedAsync += (_, e) =>
{
e.Response = new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new StringContent("Response replaced by Eavesdrop")
};
return Task.CompletedTask;
};
Cancelling Work
Both interception event args inherit from CancelEventArgs.
If a handler sets e.Cancel = true, the current pipeline operation stops and the method returns without continuing further processing for that intercepted exchange.
Supported Protocols
Currently supported:
- HTTP
- HTTPS through
CONNECTinterception and local TLS termination - HTTP/1.1 request parsing
- HTTP/1.1 chunked response streaming
Not currently supported:
- HTTP/2
- Keep-alive connection reuse
- Upgrade-based protocols such as WebSocket
Platform Notes
- The package targets
netstandard2.0,net8.0,net9.0, andnet10.0. - Windows is the primary target for machine proxy configuration and HTTPS interception workflows.
- The certificate subsystem includes Linux support, but the test suite contains a Windows-only HTTPS interception path due to TLS/platform differences.
Lifecycle and State
Useful state exposed by Eavesdropper:
ActivePortIsRunningProxyTargetsIntranetHostsPACHeader
Typical lifecycle:
Eavesdropper.Targets.Clear();
Eavesdropper.IntranetHosts.Clear();
Eavesdropper.IsProxyingTargets = false;
Eavesdropper.IsOnlyInterceptingHttp = false;
Eavesdropper.IsProxyingPrivateNetworks = false;
Eavesdropper.CertProvider.TryCreateTrustedRootCA("Eavesdrop");
Eavesdropper.Initiate(12030);
// Run application logic here.
Eavesdropper.Terminate();
Limitations and Caveats
- The API is static and global, so it is not designed for hosting multiple independent proxy instances in one process.
- Starting the proxy assumes the selected port is available; port selection and collision handling are left to the caller.
- Host filtering is enforced through the generated PAC file, so traffic that does not respect the machine proxy settings will not be intercepted.
- The default private-network PAC rules are intentionally simple and may need customization for more complex environments.
- HTTPS decryption depends on certificate trust and client behavior; some applications may still reject interception even when a root CA is installed.
Example Console App
The repository includes a simple console sample in Eavesdrop.CLI that demonstrates:
- Request and response logging
- Target filtering
- Optional private-network interception
- Optional upstream proxy forwarding
- Certificate installation and proxy start/stop flow
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
| .NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- System.Memory (>= 4.6.3)
-
net10.0
- No dependencies.
-
net8.0
- No dependencies.
-
net9.0
- No dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 2.0.0-alpha.38 | 97 | 4/15/2026 |
| 1.3.0 | 542 | 3/17/2024 |
| 1.2.2 | 397 | 11/7/2023 |
| 1.1.0 | 324 | 5/27/2023 |
| 1.0.0 | 296 | 5/18/2023 |