Table of Contents

Class HttpProxyClient

Namespace
VpnHood.Net.Proxies.HttpProxyClients
Assembly
VpnHood.Net.Proxies.dll

Opens TCP tunnels through an HTTP proxy with the CONNECT method, optionally over TLS to the proxy itself (an HTTPS proxy) and with Basic authentication.

public class HttpProxyClient : IProxyClient
Inheritance
HttpProxyClient
Implements
Inherited Members

Examples

var client = new HttpProxyClient(new HttpProxyClientOptions {
    ProxyEndPoint = proxyEndPoint,
    Username = "user", // Basic authentication, sent with every request
    Password = "pass",
    UseTls = false // true for an HTTPS proxy, with ProxyHost as the name on its certificate
});

using var tcp = new TcpClient();
await client.ConnectAsync(tcp, destinationHost, destinationPort, CancellationToken.None);

// Take the tunnel from the client: with UseTls, the connection's own stream would bypass TLS.
var stream = client.GetStream(tcp);

Remarks

One instance can serve many connections at once. With UseTls, a tunnel runs inside a TLS session, so read and write it through GetStream(TcpClient), not GetStream().

Any 2xx answer opens the tunnel. The answer is read only up to its end, so data that a destination sends first, such as an SMTP or SSH banner, stays in the stream for the caller.

Constructors

HttpProxyClient(HttpProxyClientOptions, ILogger<HttpProxyClient>?)

Opens TCP tunnels through an HTTP proxy with the CONNECT method, optionally over TLS to the proxy itself (an HTTPS proxy) and with Basic authentication.

public HttpProxyClient(HttpProxyClientOptions options, ILogger<HttpProxyClient>? logger = null)

Parameters

options HttpProxyClientOptions

The proxy's address, credentials and TLS settings.

logger ILogger<HttpProxyClient>

The logger for the client's progress and failures, or null for none.

Examples

var client = new HttpProxyClient(new HttpProxyClientOptions {
    ProxyEndPoint = proxyEndPoint,
    Username = "user", // Basic authentication, sent with every request
    Password = "pass",
    UseTls = false // true for an HTTPS proxy, with ProxyHost as the name on its certificate
});

using var tcp = new TcpClient();
await client.ConnectAsync(tcp, destinationHost, destinationPort, CancellationToken.None);

// Take the tunnel from the client: with UseTls, the connection's own stream would bypass TLS.
var stream = client.GetStream(tcp);

Remarks

One instance can serve many connections at once. With UseTls, a tunnel runs inside a TLS session, so read and write it through GetStream(TcpClient), not GetStream().

Any 2xx answer opens the tunnel. The answer is read only up to its end, so data that a destination sends first, such as an SMTP or SSH banner, stays in the stream for the caller.

Properties

ProxyEndPoint

Gets the address and port of the proxy server.

public IPEndPoint ProxyEndPoint { get; }

Property Value

IPEndPoint

Methods

CheckConnectionAsync(TcpClient, CancellationToken)

Connects to the proxy and, with UseTls, completes the TLS handshake, without asking for a tunnel.

public Task CheckConnectionAsync(TcpClient tcpClient, CancellationToken cancellationToken)

Parameters

tcpClient TcpClient

A connection that is not connected yet. With TLS, close it after the check: its TLS session is not kept, so it cannot carry a tunnel; without TLS, a tunnel can follow on it. When the check fails, it is closed.

cancellationToken CancellationToken

The token to monitor for cancellation requests.

Returns

Task

A task that represents the asynchronous operation. It completes when the check passes.

Exceptions

ArgumentNullException

tcpClient is null.

AuthenticationException

The TLS handshake with the proxy failed.

SocketException

The connection to the proxy failed.

OperationCanceledException

cancellationToken was canceled.

ConnectAsync(TcpClient, IPEndPoint, CancellationToken)

Opens a tunnel through the proxy to an IP endpoint.

public Task ConnectAsync(TcpClient tcpClient, IPEndPoint destination, CancellationToken cancellationToken)

Parameters

tcpClient TcpClient

The connection to use. When it is not connected, it is connected to ProxyEndPoint first. When the task completes, GetStream(TcpClient) gives the tunnel; when the exchange with the proxy fails, it is closed.

destination IPEndPoint

The destination's address and port.

cancellationToken CancellationToken

The token to monitor for cancellation requests.

Returns

Task

A task that represents the asynchronous operation. It completes when the tunnel is open.

Exceptions

ArgumentNullException

tcpClient or destination is null.

ArgumentOutOfRangeException

The port of destination is zero.

ProxyClientException

The proxy refused the request or did not answer as an HTTP proxy; SocketErrorCode tells why.

AuthenticationException

The TLS handshake with the proxy failed.

TimeoutException

The proxy's answer did not arrive within 30 seconds of the request.

IOException

The proxy closed the connection before its answer was complete.

SocketException

The connection to the proxy failed.

OperationCanceledException

cancellationToken was canceled.

ConnectAsync(TcpClient, string, int, CancellationToken)

Opens a tunnel through the proxy to a host, given by name or IP address.

public Task ConnectAsync(TcpClient tcpClient, string host, int port, CancellationToken cancellationToken)

Parameters

tcpClient TcpClient

The connection to use. When it is not connected, it is connected to ProxyEndPoint first. When the task completes, GetStream(TcpClient) gives the tunnel; when the exchange with the proxy fails, it is closed.

host string

The destination's host name or IP address literal. A name is sent for the proxy to resolve.

port int

The destination's port, from 1 to 65535.

cancellationToken CancellationToken

The token to monitor for cancellation requests.

Returns

Task

A task that represents the asynchronous operation. It completes when the tunnel is open.

Exceptions

ArgumentNullException

tcpClient or host is null.

ArgumentException

host is empty or white space.

ArgumentOutOfRangeException

port is less than 1 or greater than 65535.

ProxyClientException

The proxy refused the request, did not answer as an HTTP proxy, or sent headers over 8 KB; SocketErrorCode tells why. For example, 407 gives AccessDenied, and 502 gives HostUnreachable.

AuthenticationException

The TLS handshake with the proxy failed.

TimeoutException

The proxy's answer did not arrive within 30 seconds of the request.

IOException

The proxy closed the connection before its answer was complete.

SocketException

The connection to the proxy failed.

OperationCanceledException

cancellationToken was canceled.

GetStream(TcpClient)

Gets the stream that carries the tunnel of a connection opened by ConnectAsync(TcpClient, string, int, CancellationToken).

public Stream GetStream(TcpClient tcpClient)

Parameters

tcpClient TcpClient

The connection.

Returns

Stream

The TLS stream when UseTls is true; otherwise, and for a connection this client opened no tunnel on, the connection's NetworkStream.

Remarks

Dispose both: the TLS stream, whose disposal leaves the TCP connection open, and the TcpClient, which closes the tunnel.

Exceptions

ArgumentNullException

tcpClient is null.

InvalidOperationException

No tunnel of this client is on tcpClient, and it is not connected.

ObjectDisposedException

No tunnel of this client is on tcpClient, and it is disposed.