EgressSocketGuard
AgentPrism.Core.dllValidates the address a socket is about to connect to, and opens the socket only to an allowed address.
public sealed class EgressSocketGuardInheritance
Section titled “Inheritance”Inherited Members
Section titled “Inherited Members”object.GetType(), object.ToString(), object.Equals(object?), object.Equals(object?, object?), object.ReferenceEquals(object?, object?), object.GetHashCode()
Remarks
Section titled “Remarks”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.
Constructors
Section titled “Constructors”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)Parameters
Section titled “Parameters”options IOptionsMonitor<AgentPrismEgressOptions>
The egress options.
Exceptions
Section titled “Exceptions”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)Parameters
Section titled “Parameters”policyAccessor Func<EgressAddressPolicy>
Returns the policy in force. Called once per connection, so an option change takes effect without rebuilding the client.
Exceptions
Section titled “Exceptions”policyAccessor is null.
Methods
Section titled “Methods”ConnectAsync(SocketsHttpConnectionContext, CancellationToken)
Section titled “ ConnectAsync(SocketsHttpConnectionContext, CancellationToken)”The delegate to hand to SocketsHttpHandler.ConnectCallback.
public ValueTask<Stream> ConnectAsync(SocketsHttpConnectionContext context, CancellationToken cancellationToken)Parameters
Section titled “Parameters”context SocketsHttpConnectionContext
The connection context the handler supplies.
cancellationToken CancellationToken
The cancellation token.
Returns
Section titled “Returns”A stream over the connected socket.
Exceptions
Section titled “Exceptions”The target resolves to a rejected address.
CreateHandler()
Section titled “ CreateHandler()”Builds a handler whose every connection passes through this guard.
public SocketsHttpHandler CreateHandler()Returns
Section titled “Returns”The handler. The caller owns it.
Remarks
Section titled “Remarks”Every surface that reaches the network builds its client from this method. A path that built its own SocketsHttpHandler would silently be unprotected.
CreateHttpClient(TimeSpan)
Section titled “ CreateHttpClient(TimeSpan)”Builds an HttpClient whose every connection passes through this guard.
public HttpClient CreateHttpClient(TimeSpan timeout)Parameters
Section titled “Parameters”timeout TimeSpan
The response timeout to apply. Pass Timeout.InfiniteTimeSpan
only when the caller bounds every request itself.
Returns
Section titled “Returns”The client. The caller owns it and must dispose it.
Remarks
Section titled “Remarks”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.
ValidateAsync(Uri, CancellationToken)
Section titled “ ValidateAsync(Uri, CancellationToken)”Validates a target before it is stored, without opening a connection.
public ValueTask ValidateAsync(Uri target, CancellationToken cancellationToken = default)Parameters
Section titled “Parameters”target Uri
The target address.
cancellationToken CancellationToken
The cancellation token.
Returns
Section titled “Returns”Remarks
Section titled “Remarks”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.
Exceptions
Section titled “Exceptions”target is null.
The target resolves to a rejected address.