Skip to content
Open
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
112 changes: 96 additions & 16 deletions specs/WebRtcPortConfiguration.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,25 +23,26 @@ Common scenarios:

Usage steps:
1. Create `CoreWebView2EnvironmentOptions`.
2. Call `SetAllowedPortRange` for `COREWEBVIEW2_TRANSPORT_PROTOCOL_KIND_UDP`.
3. Pass the options when creating the WebView2 environment.

2. Call `SetAllowedPortRange` for `COREWEBVIEW2_NETWORK_COMPONENT_SCOPE_ALL` and `COREWEBVIEW2_TRANSPORT_PROTOCOL_KIND_UDP`.
3. Pass the options when creating the WebView2 environment.

# Examples
### C++ Configure UDP Port Range
```cpp
Microsoft::WRL::ComPtr<ICoreWebView2StagingEnvironmentOptions10> optionsStaging10;
if (options.As(&optionsStaging10) == S_OK)
{
// Configure port ranges for WebRTC UDP traffic to work within enterprise firewalls
// Configure port ranges for UDP traffic to work within enterprise firewalls
// Set UDP port range (example: 50000-55000 for enterprise environments)
const INT32 udpMin = 50000, udpMax = 55000;

CHECK_FAILURE(optionsStaging10->SetAllowedPortRange(
COREWEBVIEW2_NETWORK_COMPONENT_SCOPE_ALL,
COREWEBVIEW2_TRANSPORT_PROTOCOL_KIND_UDP, udpMin, udpMax));

// Get the configured port range
CHECK_FAILURE(optionsStaging10->GetAllowedPortRange(
COREWEBVIEW2_NETWORK_COMPONENT_SCOPE_ALL,
COREWEBVIEW2_TRANSPORT_PROTOCOL_KIND_UDP, &m_udpPortRange.minPort,
&m_udpPortRange.maxPort));
}
Expand All @@ -59,15 +60,17 @@ var options = CoreWebView2Environment.CreateCoreWebView2EnvironmentOptions();
var optionsStaging10 = options as ICoreWebView2StagingEnvironmentOptions10;
if (optionsStaging10 != null)
{
// Configure port ranges for WebRTC UDP traffic to work within enterprise firewalls
// Configure port ranges for UDP traffic to work within enterprise firewalls
// Set UDP port range (example: 50000-55000 for enterprise environments)
const int udpMin = 50000, udpMax = 55000;

optionsStaging10.SetAllowedPortRange(
COREWEBVIEW2_NETWORK_COMPONENT_SCOPE_ALL,
COREWEBVIEW2_TRANSPORT_PROTOCOL_KIND_UDP, udpMin, udpMax);

// Get the configured port range
optionsStaging10.GetAllowedPortRange(
COREWEBVIEW2_NETWORK_COMPONENT_SCOPE_ALL,
COREWEBVIEW2_TRANSPORT_PROTOCOL_KIND_UDP, out m_udpPortRange.minPort,
out m_udpPortRange.maxPort);
}
Expand All @@ -77,9 +80,47 @@ var environment = await CoreWebView2Environment.CreateAsync(
OnCreateEnvironmentCompleted(environment);
```

API Rules and Precedence

1. Network Scope param in SetAllowedPortRange
- A network component-specific scope (e.g. _WEB_RTC) always takes precedence over _ALL for that component in `SetAllowedPortRange`.
- `_ALL` defines the port range restrictions for all components without specific overrides.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think "All" enum should be named "Default" or "Unspecified" if it's not going to apply to WebRTC when _web_rtc is also set.

It's unintuitive that calling SetAllowedPortRange(ALL, 350-400); doesn't restrict the port range of WebRTC ports if WebRTC is currently restricted to 300-500, even though I'm Setting a narrower restriction on "all" component scopes.

It's unintuitive that WebRTC escapes the restriction of an existing SetAllowedPortRange(ALL, 300-400); restriction if I temporarily restrict it more narrowly (SetAllowedPortRange(WebRTC, 350-375);) and then remove that WebRTC-specific range (SetAllowedPortRange(WebRTC, 0-0);), since the original range now no longer applies to "all" scopes.

Calling the 0 value something other than "All" mitigates both of these misreadings, without having to revisit the underlying range interaction behavior you're proposing.

Copy link
Contributor Author

@ashuray007 ashuray007 Oct 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To make this clearer and avoid confusion renamed as _DEFAULT instead of _ALL and updated comments accordingly.

- Passing `(0, 0)` for a network component scope removes its restriction.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How do I block all ports?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This won't be possible today with this API.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Removes its restriction" implies "Pretend I never set a restriction".

But from the discussion below, it seems that passing (0,0) really means "set to unrestricted".

So how do I remove the restriction, i.e., set a scope to "no custom restriction; use the generic one"?

Do we need a ClearAllowedPortRange to go back to the "unset" state?

Or maybe we say that (0,0) means "remove restriction" and "0, 65535" means "explicitly unrestricted".

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated also keeping 1025 - 65535 as system Ephemeral Port Range

- If `_ALL` is set and a specific scope is reset, that component becomes unrestricted while `_ALL` still applies to others.

| Network Scope State | Behaviour |
| ------------------------------------------ | ------------------------------------------------------------------------------ |
| Only `_ALL` is set | `_ALL` applies port range restrictions to all network components |
| `_ALL` and `_WEB_RTC` are both set | `_WEB_RTC` port range restrictions applies to WebRTC; `_ALL` applies to others |
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The other candidate interaction model would be that when "All" and a specific Component both have ranges set, the effective range at runtime is the intersection of the two ranges. It's not immediately clear to me if this model would be more or less useful to developers. Just checking, have both models been considered?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We chose override instead of intersection model for below reasons

It provides explicit and predictable control: developers know exactly which range applies per component.
Intersection can silently restrict too aggressively and be harder to debug, especially if the default range and component-specific range only partially overlap.

| `_WEB_RTC` only is set | `_WEB_RTC` applies port range restrictions only to WebRTC; others unrestricted |
| `_ALL` set and `_WEB_RTC` reset to `(0,0)` | `_ALL` applies port range restrictions to all except WebRTC (unrestricted) |

2. Network Scope param in GetAllowedPortRange
- `GetAllowedPortRange` returns the range explicitly set for the queried scope.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GetEffectiveAllowedPortRange since it is not the opposite of Set but rather does calculations to determine the effect of multiple Sets.

XAML has OverflowButtonVisibility + EffectiveOverflowButtonVisibility. Also Height/Width + ActualHeight/ActualWidth.

HdcpSession has SetDesiredMinProtection + GetEffectiveProtection.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated

- If a specific scope is unset, it inherits `_ALL`.
- Querying `_ALL` only returns `_ALL`; it does not aggregate component-specific settings.
- If neither `_ALL` nor a component-specific scope is set, the default `(0,0)` (unrestricted) is returned.

| `GetAllowedPortRange` Network Scope query | Returned Range |
| ---------------------------------------------------------------- | ----------------------------- |
| Pass `_WEB_RTC` when only `_ALL` is set | Returns `_ALL` range |
| Pass `_WEB_RTC` when `_WEB_RTC` explicitly set | Returns `_WEB_RTC` range |
| Pass `_WEB_RTC` when `_ALL` unset and `_WEB_RTC` unset | Returns `(0, 0)` |
| Pass `_WEB_RTC` when `_ALL` set and `_WEB_RTC` reset to `(0, 0)` | Returns `(0, 0)` |
| Pass `_ALL` when only `_WEB_RTC` set | Returns `(0,0)` |

# API Details
### C++
```
/// Specifies the network component scope for port configuration.
[v1_enum]
typedef enum COREWEBVIEW2_NETWORK_COMPONENT_SCOPE {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Network component scope" seems more generic than what it's being used for in this API. Is this enum feasibly reusable in another future API or should this be CoreWebview2AllowedPortRangeKind ?

Copy link
Contributor Author

@ashuray007 ashuray007 Oct 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At this point, the enum is designed specifically for port-range configuration.
We don’t expect it to be reused broadly across other APIs.
To make its purpose clearer, we can rename it to: CoreWebview2AllowedPortRangeScope

/// Scope applies to all components.
COREWEBVIEW2_NETWORK_COMPONENT_SCOPE_ALL,
/// Applies only to WebRTC peer-to-peer connection.
COREWEBVIEW2_NETWORK_COMPONENT_SCOPE_WEB_RTC,
} COREWEBVIEW2_NETWORK_COMPONENT_SCOPE;

/// Specifies the network protocol for port configuration.
[v1_enum]
typedef enum COREWEBVIEW2_TRANSPORT_PROTOCOL_KIND {
Expand All @@ -88,28 +129,46 @@ typedef enum COREWEBVIEW2_TRANSPORT_PROTOCOL_KIND {
} COREWEBVIEW2_TRANSPORT_PROTOCOL_KIND;

/// Additional options used to create WebView2 Environment to manage port range configuration.
[uuid(eaf22436-27a1-5e3d-a4e3-84d7e7a69a1a), object, pointer_default(unique)]
[uuid(6ce30f6b-5dcc-5dc1-9c09-723cf233dbe5), object, pointer_default(unique)]
interface ICoreWebView2StagingEnvironmentOptions10 : IUnknown {
/// Sets the allowed port range for the specified transport protocol.
/// Sets the allowed port range restriction for the specified network component
/// scope and transport protocol.
///
/// This API enables WebView2 to operate within enterprise network or firewall
/// restrictions by limiting network communication to a defined port range.
/// It provides fine-grained control by allowing port restrictions to be applied
/// per network component scope, such as WebRTC.
///
/// Currently, only WebRTC UDP Port Range restriction is supported.
///
/// `minPort` and `maxPort` must be within the range 1025–65535 (inclusive),
/// and `minPort` must be less than or equal to `maxPort`.
/// `minPort` and `maxPort` must be within the range 1025-65535 (inclusive).
/// `minPort` must be less than or equal to `maxPort`.
/// If `minPort` equals `maxPort`, the range represents a single port.
///
/// Passing `(0, 0)` resets to the default behavior, meaning no restrictions
/// are applied and the system assigns ports from the full ephemeral range.
///
/// Calls with invalid ranges fail with `E_INVALIDARG`.
///
/// `protocol` The transport protocol (currently only UDP is supported).
///
/// A network component-specific scope (e.g. _WEB_RTC) always takes precedence over _ALL for that component in `SetAllowedPortRange`.
/// `_ALL` defines the port range restrictions for all components without specific overrides.
/// Passing `(0, 0)` for a network component scope removes its restriction.
/// If `_ALL` is set and a specific scope is reset, that component becomes unrestricted while `_ALL` still applies to others.

/// | Network Scope State | Behaviour |
/// | ------------------------------------------ | ------------------------------------------------------------------------------ |
/// | Only `_ALL` is set | `_ALL` applies port range restrictions to all network components |
/// | `_ALL` and `_WEB_RTC` are both set | `_WEB_RTC` port range restrictions applies to WebRTC; `_ALL` applies to others |
/// | `_WEB_RTC` only is set | `_WEB_RTC` applies port range restrictions only to WebRTC; others unrestricted |
/// | `_ALL` set and `_WEB_RTC` reset to `(0,0)` | `_ALL` applies port range restrictions to all except WebRTC (unrestricted) |

/// `scope` Network scope on which restrictions will apply.
/// `protocol` Transport protocol on which restrictions will apply.
/// `minPort` The minimum allowed port number (inclusive).
/// `maxPort` The maximum allowed port number (inclusive).
///
HRESULT SetAllowedPortRange(
[in] COREWEBVIEW2_NETWORK_COMPONENT_SCOPE scope,
[in] COREWEBVIEW2_TRANSPORT_PROTOCOL_KIND protocol,
[in] INT32 minPort,
[in] INT32 maxPort
Expand All @@ -120,13 +179,28 @@ interface ICoreWebView2StagingEnvironmentOptions10 : IUnknown {
/// `SetAllowedPortRange`.
///
/// By default, `(0, 0)` is returned, which indicates no restrictions are applied
/// and ports are allocated from the system’s ephemeral range (1025–65535 inclusive).
///
/// `protocol` The transport protocol (currently only UDP is supported).
/// and ports are allocated from the system's ephemeral range (1025-65535 inclusive).
///
/// `GetAllowedPortRange` returns the range explicitly set for the queried scope.
/// If a specific scope is unset, it inherits `_ALL`.
/// Querying `_ALL` only returns `_ALL`; it does not aggregate component-specific settings.
/// If neither `_ALL` nor a component-specific scope is set, the default `(0,0)` (unrestricted) is returned.

/// | `GetAllowedPortRange` Network Scope query | Returned Range |
/// | ---------------------------------------------------------------- | ----------------------------- |
/// | Pass `_WEB_RTC` when only `_ALL` is set | Returns `_ALL` range |
/// | Pass `_WEB_RTC` when `_WEB_RTC` explicitly set | Returns `_WEB_RTC` range |
/// | Pass `_WEB_RTC` when `_ALL` unset and `_WEB_RTC` unset | Returns `(0, 0)` |
/// | Pass `_WEB_RTC` when `_ALL` set and `_WEB_RTC` reset to `(0, 0)` | Returns `(0, 0)` |
/// | Pass `_ALL` when only `_WEB_RTC` set | Returns `(0,0)` |

/// `scope` Network scope on which restrictions is applied.
/// `protocol` Transport protocol on which restrictions is applied.
/// `minPort` Receives the minimum allowed port number (inclusive).
/// `maxPort` Receives the maximum allowed port number (inclusive).
///
HRESULT GetAllowedPortRange(
[in] COREWEBVIEW2_NETWORK_COMPONENT_SCOPE scope,
[in] COREWEBVIEW2_TRANSPORT_PROTOCOL_KIND protocol,
[out] INT32* minPort,
[out] INT32* maxPort
Expand All @@ -140,6 +214,12 @@ interface ICoreWebView2StagingEnvironmentOptions10 : IUnknown {
```csharp
namespace Microsoft.Web.WebView2.Core
{
enum CoreWebview2NetworkComponentScope
{
All = 0,
WebRtc = 1,
};

enum CoreWebView2TransportProtocolKind
{
Udp = 0,
Expand All @@ -150,8 +230,8 @@ namespace Microsoft.Web.WebView2.Core
[interface_name("Microsoft.Web.WebView2.Core.ICoreWebView2StagingEnvironmentOptions10")]
{
// ICoreWebView2StagingEnvironmentOptions10 members
void SetAllowedPortRange(CoreWebView2TransportProtocolKind protocol, Int32 minPort, Int32 maxPort);
void GetAllowedPortRange(CoreWebView2TransportProtocolKind protocol, out Int32 minPort, out Int32 maxPort);
void SetAllowedPortRange(CoreWebview2NetworkComponentScope scope, CoreWebView2TransportProtocolKind protocol, Int32 minPort, Int32 maxPort);
void GetAllowedPortRange(CoreWebview2NetworkComponentScope scope, CoreWebView2TransportProtocolKind protocol, out Int32 minPort, out Int32 maxPort);
}
}
}
Expand Down