Skip to content

EgressSocketGuard

Namespace AgentPrism · Assembly AgentPrism.Core.dll

Validates the address a socket is about to connect to, and opens the socket only to an allowed address.

public sealed class EgressSocketGuard

objectEgressSocketGuard

object.GetType(), object.ToString(), object.Equals(object?), object.Equals(object?, object?), object.ReferenceEquals(object?, object?), object.GetHashCode()

The check happening here — inside SocketsHttpHandler.ConnectCallback — is the whole point. Validating an address first and then calling HttpClient.SendAsync(url) leaves a TOCTOU gap: HttpClient resolves the name a second time, and an attacker can change the answer between the two resolutions (DNS rebinding). The address validated in the connection callback is the very address the socket connects to; there is no further resolution in between.

IHttpClientFactory is deliberately not used, for two reasons: it would add Microsoft.Extensions.Http to the dependency graph, and a consumer reconfiguring the named client could silently remove the protection.

The Host header is set from, and preserved as, the original name by HttpClient; TLS validation is also performed against the original name.

EgressSocketGuard(IOptionsMonitor<AgentPrismEgressOptions>)

Section titled “ EgressSocketGuard(IOptionsMonitor<AgentPrismEgressOptions>)”

Creates a guard that reads its policy from the shared egress options.

public EgressSocketGuard(IOptionsMonitor<AgentPrismEgressOptions> options)

options IOptionsMonitor<AgentPrismEgressOptions>

The egress options.

ArgumentNullException

options is null.

EgressSocketGuard(Func<EgressAddressPolicy>)

Section titled “ EgressSocketGuard(Func<EgressAddressPolicy>)”

Creates a guard whose policy is read fresh on every connection.

public EgressSocketGuard(Func<EgressAddressPolicy> policyAccessor)

policyAccessor Func<EgressAddressPolicy>

Returns the policy in force. Called once per connection, so an option change takes effect without rebuilding the client.

ArgumentNullException

policyAccessor is null.

ConnectAsync(SocketsHttpConnectionContext, CancellationToken)

Section titled “ ConnectAsync(SocketsHttpConnectionContext, CancellationToken)”

The delegate to hand to SocketsHttpHandler.ConnectCallback.

public ValueTask<Stream> ConnectAsync(SocketsHttpConnectionContext context, CancellationToken cancellationToken)

context SocketsHttpConnectionContext

The connection context the handler supplies.

cancellationToken CancellationToken

The cancellation token.

ValueTask<Stream>

A stream over the connected socket.

AgentPrismException

The target resolves to a rejected address.

Builds a handler whose every connection passes through this guard.

public SocketsHttpHandler CreateHandler()

SocketsHttpHandler

The handler. The caller owns it.

Every surface that reaches the network builds its client from this method. A path that built its own SocketsHttpHandler would silently be unprotected.

Builds an HttpClient whose every connection passes through this guard.

public HttpClient CreateHttpClient(TimeSpan timeout)

timeout TimeSpan

The response timeout to apply. Pass Timeout.InfiniteTimeSpan only when the caller bounds every request itself.

HttpClient

The client. The caller owns it and must dispose it.

The timeout is explicit rather than defaulted, because replacing the transport of an SDK also replaces whatever timeout that SDK’s own client carried. A caller that inherits an infinite timeout by accident hangs forever on a server that accepts a connection and never answers.

Validates a target before it is stored, without opening a connection.

public ValueTask ValidateAsync(Uri target, CancellationToken cancellationToken = default)

target Uri

The target address.

cancellationToken CancellationToken

The cancellation token.

ValueTask

This is a convenience for callers that already hold a resolved target. The save-time endpoints use EgressAddressValidator.ValidateLiteral instead, so that a name which does not resolve yet is not rejected.

ArgumentNullException

target is null.

AgentPrismException

The target resolves to a rejected address.