Table of Contents

Class WindowsVpnPluginAdapter

Namespace
VpnHood.Net.VpnAdapters.WindowsVpnPlugin
Assembly
VpnHood.Net.VpnAdapters.WindowsVpnPlugin.dll

Provides the VPN adapter of a Windows VPN plug-in, on the VpnChannel Windows gives the plug-in's connect: Windows owns the interface, and the adapter starts the channel with the addresses, routes, DNS servers and MTU a start gathers.

public sealed class WindowsVpnPluginAdapter : TunVpnAdapter, IVpnAdapter, IPacketTransport, IDisposable
Inheritance
WindowsVpnPluginAdapter
Implements
Inherited Members

Remarks

Windows hands the device's outgoing packets to the plug-in's Encapsulate callback, which passes them to OnEncapsulate(VpnPacketBufferList, VpnPacketBufferList); the adapter queues copies for its reader, and writes incoming packets into the channel's receive buffers. The channel's transport is a UDP socket connected to the VPN server's address, which carries no data. The MTU is at most 1,400 bytes. There is no NAT and no app filter.

A close leaves the channel up: the plug-in stops it in Windows' Disconnect, as Windows takes a channel stopped by itself for a dropped connection and dials again.

Constructors

WindowsVpnPluginAdapter(VpnChannel, VpnAdapterSettings)

Provides the VPN adapter of a Windows VPN plug-in, on the VpnChannel Windows gives the plug-in's connect: Windows owns the interface, and the adapter starts the channel with the addresses, routes, DNS servers and MTU a start gathers.

public WindowsVpnPluginAdapter(VpnChannel vpnChannel, VpnAdapterSettings adapterSettings)

Parameters

vpnChannel VpnChannel

The channel Windows gave the plug-in's connect.

adapterSettings VpnAdapterSettings

The adapter's settings.

Remarks

Windows hands the device's outgoing packets to the plug-in's Encapsulate callback, which passes them to OnEncapsulate(VpnPacketBufferList, VpnPacketBufferList); the adapter queues copies for its reader, and writes incoming packets into the channel's receive buffers. The channel's transport is a UDP socket connected to the VPN server's address, which carries no data. The MTU is at most 1,400 bytes. There is no NAT and no app filter.

A close leaves the channel up: the plug-in stops it in Windows' Disconnect, as Windows takes a channel stopped by itself for a dropped connection and dials again.

Exceptions

ArgumentOutOfRangeException

The settings' blocking timeout is negative or too long, or their queue capacity is not above zero.

Properties

AppPackageId

Gets the ID the app filter knows this app by, which it always lets into the tunnel, or null where there is no app filter.

protected override string? AppPackageId { get; }

Property Value

string

Always null: there is no app filter.

Exceptions

ArgumentOutOfRangeException

The settings' blocking timeout is negative or too long, or their queue capacity is not above zero.

CheckAdapterInterfaceAfterNetworkChanged

Gets a value indicating whether the adapter checks, at each change of the host's network, that its interface is still there, and stops when it is not. The check is IsAdapterInterfaceEnabled(), which by default looks for the interface by name or address only.

protected override bool CheckAdapterInterfaceAfterNetworkChanged { get; }

Property Value

bool

Always false.

Exceptions

ArgumentOutOfRangeException

The settings' blocking timeout is negative or too long, or their queue capacity is not above zero.

IsAppFilterSupported

Gets a value indicating whether the adapter can include or exclude apps from the tunnel (IncludeApps, ExcludeApps).

public override bool IsAppFilterSupported { get; }

Property Value

bool

Always false.

Exceptions

ArgumentOutOfRangeException

The settings' blocking timeout is negative or too long, or their queue capacity is not above zero.

IsSocketProtectedByBind

Gets a value indicating whether the adapter keeps a socket out of the tunnel by binding it to the primary address, rather than by an OS call of its own.

protected override bool IsSocketProtectedByBind { get; }

Property Value

bool

Always true: the VPN host's own sockets leave by the physical adapter, bound to its address.

Remarks

When true, the routes leave out the probe networks the adapter aims at to find the primary addresses, and that search runs on an unprotected socket after a network change.

Exceptions

ArgumentOutOfRangeException

The settings' blocking timeout is negative or too long, or their queue capacity is not above zero.

RestartAfterNetworkAddressChanged

Gets a value indicating whether the adapter restarts when the host moves to other networks. When false, it takes the new primary addresses and raises PrimaryNetworkChanged.

protected override bool RestartAfterNetworkAddressChanged { get; }

Property Value

bool

Always false: Windows owns the interface, its addresses and their changes.

Exceptions

ArgumentOutOfRangeException

The settings' blocking timeout is negative or too long, or their queue capacity is not above zero.

StartedTask

Gets a task that completes when the channel has started, at the end of a successful open, before the reader starts and Started is raised; it is canceled when the adapter closes or is disposed first.

public Task StartedTask { get; }

Property Value

Task

Remarks

An open that finds the task completed or canceled makes a new one as it begins, so read the property again once a later start has reached its open. A stop before any start does not cancel the task.

Exceptions

ArgumentOutOfRangeException

The settings' blocking timeout is negative or too long, or their queue capacity is not above zero.

Methods

AdapterAdd(CancellationToken)

Makes the interface: the first step of a start.

protected override Task AdapterAdd(CancellationToken cancellationToken)

Parameters

cancellationToken CancellationToken

The token to monitor for cancellation requests.

Returns

Task

A task that represents the asynchronous operation.

Remarks

It makes no interface, as Windows owns it: it forgets the settings an earlier start gathered, sets the MTU back to 1,400 bytes, and keeps the packet queue closed until the open.

Exceptions

ArgumentOutOfRangeException

The settings' blocking timeout is negative or too long, or their queue capacity is not above zero.

AdapterClose()

Closes the interface for reading and writing: the first step of a stop, under the base's stop lock. It may run after a partial start.

protected override void AdapterClose()

Remarks

It closes the packet queue, dropping the packets in it, waits up to a second for a batch being sent, which it logs when the batch is late, cancels StartedTask if it has not completed, and disposes the channel's transport socket. The channel stays up.

Exceptions

ArgumentOutOfRangeException

The settings' blocking timeout is negative or too long, or their queue capacity is not above zero.

AdapterOpen(CancellationToken)

Opens the interface for reading and writing packets: the last step of a start, before the reader starts.

protected override Task AdapterOpen(CancellationToken cancellationToken)

Parameters

cancellationToken CancellationToken

The token to monitor for cancellation requests.

Returns

Task

A task that represents the asynchronous operation.

Remarks

It associates a new UDP socket with the channel as its transport and connects it to the VPN server's address, then starts the channel with the gathered addresses, routes, DNS servers and MTU, opens the packet queue, and completes StartedTask. A packet Windows hands over during the channel's start is dropped.

Exceptions

InvalidOperationException

The run's options name no VPN server address.

OperationCanceledException

cancellationToken was canceled while the socket was bound or connected.

AdapterRemove()

Removes the interface and what the start added with it: the last step of a stop, after AdapterClose(). When the base calls it, it runs under the base's stop lock and must not wait for the reader or a sender to take that lock. It may run after a partial start, and after a close that failed.

protected override void AdapterRemove()

Remarks

It does nothing: Windows owns the interface and the channel.

Exceptions

ArgumentOutOfRangeException

The settings' blocking timeout is negative or too long, or their queue capacity is not above zero.

AddAddress(IpNetwork, CancellationToken)

Gives the interface its address in a virtual network. A start calls it once per configured IP version.

protected override Task AddAddress(IpNetwork ipNetwork, CancellationToken cancellationToken)

Parameters

ipNetwork IpNetwork

The interface's address with its network.

cancellationToken CancellationToken

The token to monitor for cancellation requests.

Returns

Task

A task that represents the asynchronous operation.

Remarks

It keeps the address, not its network's prefix length, for the open, which hands it to Windows.

Exceptions

ArgumentOutOfRangeException

The settings' blocking timeout is negative or too long, or their queue capacity is not above zero.

AddNat(IpNetwork, CancellationToken)

Translates a virtual network to the host's primary address (NAT). A start calls it with UseNat, for each IP version the adapter's NAT translates and the host has a primary address of.

protected override Task AddNat(IpNetwork ipNetwork, CancellationToken cancellationToken)

Parameters

ipNetwork IpNetwork

The virtual network.

cancellationToken CancellationToken

The token to monitor for cancellation requests.

Returns

Task

A task that represents the asynchronous operation.

Exceptions

NotSupportedException

Always: the adapter has no NAT.

AddRoute(IpNetwork, CancellationToken)

Routes a network through the interface. A start calls it once per network, for each IP version the interface carries.

protected override Task AddRoute(IpNetwork ipNetwork, CancellationToken cancellationToken)

Parameters

ipNetwork IpNetwork

The network.

cancellationToken CancellationToken

The token to monitor for cancellation requests.

Returns

Task

A task that represents the asynchronous operation.

Remarks

It keeps the route for the open, which hands it to Windows.

Exceptions

ArgumentOutOfRangeException

The settings' blocking timeout is negative or too long, or their queue capacity is not above zero.

DisposeManaged()

Stops watching the host's network changes, raises Disposed, then disposes the transport.

protected override void DisposeManaged()

Remarks

It cancels StartedTask if it has not completed.

Exceptions

ArgumentOutOfRangeException

The settings' blocking timeout is negative or too long, or their queue capacity is not above zero.

IsNatSupported(IpVersion)

Determines whether the adapter's NAT translates an IP version. A server forwards a version the adapter does not translate by its own forwarders.

public override bool IsNatSupported(IpVersion ipVersion)

Parameters

ipVersion IpVersion

The IP version.

Returns

bool

true if the adapter translates it; otherwise, false.

Remarks

Always false.

Exceptions

ArgumentOutOfRangeException

The settings' blocking timeout is negative or too long, or their queue capacity is not above zero.

OnEncapsulate(VpnPacketBufferList, VpnPacketBufferList)

Takes the device's outgoing packets Windows hands to the plug-in's Encapsulate callback: it queues a copy of each for the adapter's reader, and leaves the buffers in packets, where Windows takes them back.

public void OnEncapsulate(VpnPacketBufferList packets, VpnPacketBufferList encapsulatedPackets)

Parameters

packets VpnPacketBufferList

The packets, whose buffers stay in the list, in their order when the call reads them all.

encapsulatedPackets VpnPacketBufferList

The list whose buffers Windows sends through the channel's transport; the adapter adds none.

Remarks

While the adapter is not open, the packets are left to Windows unread. After copying a packet, the call checks whether the adapter has closed or opened again since it began; if so, it discards the copy and leaves the rest unread. A packet is dropped when the queue is full: it holds QueueCapacity packets, or 256 if that is fewer or not set; the first such drop of an open is logged. An empty buffer is skipped. Windows may call it after a close or a disposal.

Exceptions

ArgumentOutOfRangeException

The settings' blocking timeout is negative or too long, or their queue capacity is not above zero.

ReadPacket(byte[])

Reads one packet from the interface into a buffer, without waiting for one.

protected override int ReadPacket(byte[] buffer)

Parameters

buffer byte[]

The buffer, at least the MTU long.

Returns

int

The number of bytes read, from the buffer's start; 0 if no packet is ready.

Remarks

Only the bytes read are parsed, and a packet whose header claims more is refused: the buffer is rented, so past them it holds an earlier read's bytes.

Exceptions

ArgumentOutOfRangeException

The settings' blocking timeout is negative or too long, or their queue capacity is not above zero.

SetAllowedApps(IEnumerable<string>, CancellationToken)

Lets only these apps' traffic into the tunnel. A start calls it with IncludeApps, where IsAppFilterSupported is true.

protected override Task SetAllowedApps(IEnumerable<string> packageIds, CancellationToken cancellationToken)

Parameters

packageIds IEnumerable<string>

The apps' IDs, this app's own included.

cancellationToken CancellationToken

The token to monitor for cancellation requests.

Returns

Task

A task that represents the asynchronous operation.

Exceptions

NotSupportedException

Always: the adapter has no app filter.

SetDisallowedApps(IEnumerable<string>, CancellationToken)

Keeps these apps' traffic out of the tunnel. A start calls it with ExcludeApps, where IsAppFilterSupported is true.

protected override Task SetDisallowedApps(IEnumerable<string> packageIds, CancellationToken cancellationToken)

Parameters

packageIds IEnumerable<string>

The apps' IDs, never this app's own.

cancellationToken CancellationToken

The token to monitor for cancellation requests.

Returns

Task

A task that represents the asynchronous operation.

Exceptions

NotSupportedException

Always: the adapter has no app filter.

SetDnsServers(IReadOnlyList<IPAddress>, CancellationToken)

Sets the DNS servers the interface gives the host. A start calls it every time.

protected override Task SetDnsServers(IReadOnlyList<IPAddress> dnsServers, CancellationToken cancellationToken)

Parameters

dnsServers IReadOnlyList<IPAddress>

The servers, only of the IP versions the interface carries; may be empty.

cancellationToken CancellationToken

The token to monitor for cancellation requests.

Returns

Task

A task that represents the asynchronous operation.

Remarks

It keeps the servers for the open, which makes them the servers of every domain. Each server the routes include also gets a host route of its own in the channel, as Windows routes the physical adapter's DNS servers around the channel by host routes while it is connected.

Exceptions

ArgumentOutOfRangeException

The settings' blocking timeout is negative or too long, or their queue capacity is not above zero.

SetMetric(int, bool, bool, CancellationToken)

Sets the interface's route metric. A start calls it when Metric is set.

protected override Task SetMetric(int metric, bool ipV4, bool ipV6, CancellationToken cancellationToken)

Parameters

metric int

The metric.

ipV4 bool

true if the interface carries IPv4 in this run.

ipV6 bool

true if the interface carries IPv6 in this run.

cancellationToken CancellationToken

The token to monitor for cancellation requests.

Returns

Task

A task that represents the asynchronous operation.

Remarks

It does nothing: Windows gives the channel's interface its metric, unless the VPN profile names one.

Exceptions

ArgumentOutOfRangeException

The settings' blocking timeout is negative or too long, or their queue capacity is not above zero.

SetMtu(int, bool, bool, CancellationToken)

Sets the interface's MTU. A start calls it when Mtu is set.

protected override Task SetMtu(int mtu, bool ipV4, bool ipV6, CancellationToken cancellationToken)

Parameters

mtu int

The MTU in bytes.

ipV4 bool

true if the interface carries IPv4 in this run.

ipV6 bool

true if the interface carries IPv6 in this run.

cancellationToken CancellationToken

The token to monitor for cancellation requests.

Returns

Task

A task that represents the asynchronous operation.

Remarks

It keeps the MTU for the open, at most 1,400 bytes, the size tested with packets end to end.

Exceptions

ArgumentOutOfRangeException

The settings' blocking timeout is negative or too long, or their queue capacity is not above zero.

SetSessionName(string, CancellationToken)

Names the session where the OS shows it. A start calls it when SessionName is not empty.

protected override Task SetSessionName(string sessionName, CancellationToken cancellationToken)

Parameters

sessionName string

The name.

cancellationToken CancellationToken

The token to monitor for cancellation requests.

Returns

Task

A task that represents the asynchronous operation.

Remarks

It writes the name to the channel's diagnostic log.

Exceptions

ArgumentOutOfRangeException

The settings' blocking timeout is negative or too long, or their queue capacity is not above zero.

WaitForTunRead()

Blocks until a packet may be ready, after a read found none. It runs on the reader's task.

protected override void WaitForTunRead()

Remarks

It waits up to a second for a packet to be queued; a close wakes it.

Exceptions

ArgumentOutOfRangeException

The settings' blocking timeout is negative or too long, or their queue capacity is not above zero.

WaitForTunWrite()

Blocks until the interface may take a packet again, between the retries of a write it refused.

protected override void WaitForTunWrite()

Remarks

It sleeps a millisecond.

Exceptions

ArgumentOutOfRangeException

The settings' blocking timeout is negative or too long, or their queue capacity is not above zero.

WritePacket(IpPacket)

Writes one packet to the interface, without waiting for room.

protected override bool WritePacket(IpPacket ipPacket)

Parameters

ipPacket IpPacket

The packet.

Returns

bool

true if the interface took it; false if it cannot take it now, which the adapter retries with doubling waits (see MaxPacketSendDelay).

Remarks

Windows' receive buffers run out when the VPN host falls behind, as while Windows freezes it between VPN events; a dropped packet is lost, unless its sender, as TCP's does, sends it again.

Exceptions

ArgumentOutOfRangeException

The settings' blocking timeout is negative or too long, or their queue capacity is not above zero.