dotnet / runtime

.NET is a cross-platform runtime for cloud, mobile, desktop, and IoT apps.
https://docs.microsoft.com/dotnet/core/
MIT License
14.91k stars 4.63k forks source link

QUIC: Port 50009 throws QUIC_STATUS_ADDRESS_IN_USE #71518

Open JamesNK opened 2 years ago

JamesNK commented 2 years ago

Description

In .NET 6 I have unit tests that start a Kestrel HTTP/3 endpoint on port 50019. It works fine.

I updated the unit test to .NET 7 and it now throws QUIC_STATUS_ADDRESS_IN_USE. Why is that? Is it a bug, or intentional behavior? If it's intentional then there should be documentation about what ports can be used.

Reproduction Steps

Small modification to the empty ASP.NET Core template to add a H3 port:

var builder = WebApplication.CreateBuilder(args);
builder.WebHost.ConfigureKestrel(c =>
{
    c.ListenLocalhost(50009, listner =>
    {
        listner.Protocols = Microsoft.AspNetCore.Server.Kestrel.Core.HttpProtocols.Http3;
        listner.UseHttps();
    });
});
var app = builder.Build();

app.MapGet("/", () => "Hello World!");

app.Run();

Expected behavior

Works

Actual behavior

System.IO.IOException
  HResult=0x80131620
  Message=Failed to bind to address https://localhost:50009.
  Source=Microsoft.AspNetCore.Server.Kestrel.Core
  StackTrace:
   at Microsoft.AspNetCore.Server.Kestrel.Core.LocalhostListenOptions.<BindAsync>d__2.MoveNext()
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.AddressBinder.EndpointsStrategy.<BindAsync>d__2.MoveNext()
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.AddressBinder.<BindAsync>d__0.MoveNext()
   at Microsoft.AspNetCore.Server.Kestrel.Core.KestrelServerImpl.<BindAsync>d__33.MoveNext()
   at Microsoft.AspNetCore.Server.Kestrel.Core.KestrelServerImpl.<StartAsync>d__30`1.MoveNext()
   at Microsoft.AspNetCore.Hosting.GenericWebHostService.<StartAsync>d__37.MoveNext()
   at Microsoft.Extensions.Hosting.Internal.Host.<StartAsync>d__12.MoveNext()
   at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.<RunAsync>d__4.MoveNext()
   at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.<RunAsync>d__4.MoveNext()
   at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.Run(IHost host)
   at Program.<Main>$(String[] args) in C:\Users\james\source\repos\WebApplication6\WebApplication6\Program.cs:line 14

  This exception was originally thrown at this call stack:
    Microsoft.Quic.MsQuic.ThrowIfFailure(int, string)
    System.Net.Quic.Implementations.MsQuic.MsQuicListener.Start(System.Net.Quic.QuicListenerOptions)
    System.Net.Quic.Implementations.MsQuic.MsQuicListener.MsQuicListener(System.Net.Quic.QuicListenerOptions)
    System.Net.Quic.QuicListener.ListenAsync(System.Net.Quic.QuicListenerOptions, System.Threading.CancellationToken)
    Microsoft.AspNetCore.Server.Kestrel.Transport.Quic.Internal.QuicConnectionListener.CreateListenerAsync()
    Microsoft.AspNetCore.Server.Kestrel.Transport.Quic.QuicTransportFactory.BindAsync(System.Net.EndPoint, Microsoft.AspNetCore.Http.Features.IFeatureCollection, System.Threading.CancellationToken)
    System.Threading.Tasks.ValueTask<TResult>.Result.get()
    Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure.TransportManager.BindAsync(System.Net.EndPoint, Microsoft.AspNetCore.Connections.MultiplexedConnectionDelegate, Microsoft.AspNetCore.Server.Kestrel.Core.ListenOptions, System.Threading.CancellationToken)
    Microsoft.AspNetCore.Server.Kestrel.Core.KestrelServerImpl.StartAsync.__OnBind|0(Microsoft.AspNetCore.Server.Kestrel.Core.ListenOptions, System.Threading.CancellationToken)
    Microsoft.AspNetCore.Server.Kestrel.Core.Internal.AddressBinder.BindEndpointAsync(Microsoft.AspNetCore.Server.Kestrel.Core.ListenOptions, Microsoft.AspNetCore.Server.Kestrel.Core.Internal.AddressBindContext, System.Threading.CancellationToken)
    ...
    [Call Stack Truncated]

Inner Exception 1:
AggregateException: One or more errors occurred.

Inner Exception 2:
MsQuicException: ListenerStart failed: QUIC_STATUS_ADDRESS_IN_USE

Regression?

Yes

Known Workarounds

Use a different port

Configuration

No response

Other information

No response

ghost commented 2 years ago

Tagging subscribers to this area: @dotnet/ncl See info in area-owners.md if you want to be subscribed.

Issue Details
### Description In .NET 6 I have unit tests that start Kestrel on port 50019. I works fine. I updated the unit test to .NET 7 and it now throws QUIC_STATUS_ADDRESS_IN_USE. Why is that? Is it a bug, or intentional behavior? If it's intentional then there should be documentation about what ports can be used. ### Reproduction Steps ```cs var builder = WebApplication.CreateBuilder(args); builder.WebHost.ConfigureKestrel(c => { c.ListenLocalhost(50009, listner => { listner.Protocols = Microsoft.AspNetCore.Server.Kestrel.Core.HttpProtocols.Http3; listner.UseHttps(); }); }); var app = builder.Build(); app.MapGet("/", () => "Hello World!"); app.Run(); ``` ### Expected behavior Works ### Actual behavior ``` System.IO.IOException HResult=0x80131620 Message=Failed to bind to address https://localhost:50009. Source=Microsoft.AspNetCore.Server.Kestrel.Core StackTrace: at Microsoft.AspNetCore.Server.Kestrel.Core.LocalhostListenOptions.d__2.MoveNext() at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.AddressBinder.EndpointsStrategy.d__2.MoveNext() at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.AddressBinder.d__0.MoveNext() at Microsoft.AspNetCore.Server.Kestrel.Core.KestrelServerImpl.d__33.MoveNext() at Microsoft.AspNetCore.Server.Kestrel.Core.KestrelServerImpl.d__30`1.MoveNext() at Microsoft.AspNetCore.Hosting.GenericWebHostService.d__37.MoveNext() at Microsoft.Extensions.Hosting.Internal.Host.d__12.MoveNext() at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.d__4.MoveNext() at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.d__4.MoveNext() at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.Run(IHost host) at Program.
$(String[] args) in C:\Users\james\source\repos\WebApplication6\WebApplication6\Program.cs:line 14 This exception was originally thrown at this call stack: Microsoft.Quic.MsQuic.ThrowIfFailure(int, string) System.Net.Quic.Implementations.MsQuic.MsQuicListener.Start(System.Net.Quic.QuicListenerOptions) System.Net.Quic.Implementations.MsQuic.MsQuicListener.MsQuicListener(System.Net.Quic.QuicListenerOptions) System.Net.Quic.QuicListener.ListenAsync(System.Net.Quic.QuicListenerOptions, System.Threading.CancellationToken) Microsoft.AspNetCore.Server.Kestrel.Transport.Quic.Internal.QuicConnectionListener.CreateListenerAsync() Microsoft.AspNetCore.Server.Kestrel.Transport.Quic.QuicTransportFactory.BindAsync(System.Net.EndPoint, Microsoft.AspNetCore.Http.Features.IFeatureCollection, System.Threading.CancellationToken) System.Threading.Tasks.ValueTask.Result.get() Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure.TransportManager.BindAsync(System.Net.EndPoint, Microsoft.AspNetCore.Connections.MultiplexedConnectionDelegate, Microsoft.AspNetCore.Server.Kestrel.Core.ListenOptions, System.Threading.CancellationToken) Microsoft.AspNetCore.Server.Kestrel.Core.KestrelServerImpl.StartAsync.__OnBind|0(Microsoft.AspNetCore.Server.Kestrel.Core.ListenOptions, System.Threading.CancellationToken) Microsoft.AspNetCore.Server.Kestrel.Core.Internal.AddressBinder.BindEndpointAsync(Microsoft.AspNetCore.Server.Kestrel.Core.ListenOptions, Microsoft.AspNetCore.Server.Kestrel.Core.Internal.AddressBindContext, System.Threading.CancellationToken) ... [Call Stack Truncated] Inner Exception 1: AggregateException: One or more errors occurred. Inner Exception 2: MsQuicException: ListenerStart failed: QUIC_STATUS_ADDRESS_IN_USE ``` ### Regression? Yes ### Known Workarounds Use a different port ### Configuration _No response_ ### Other information _No response_
Author: JamesNK
Assignees: -
Labels: `untriaged`, `area-System.Net.Quic`
Milestone: -
JamesNK commented 2 years ago

The fix in my unit test project was to change the port to 55019.

Why 55019 works and 50019 now doesn't.... 🤷‍♂️

wfurt commented 2 years ago

did you try to dump ports using netstat? AFAIK this error comes from Kernel. This could be sign of some old process sticking around.

JamesNK commented 2 years ago

50019 with .NET 6 = works 50019 with .NET 7 = error

I flipped back and forth a number of times to check that it was changing the .NET version that triggered it and nothing else. And I changed the port to a couple of other similar values, e.g. 50018, before discovering a bigger change like 55019 worked. Perhaps msquic doesn't allow listening on a range of ports by default?

I didn't use netstat.

The QUIC_STATUS_ADDRESS_IN_USE error is coming from MsQuicListener. It's in the stacktrace.

Repo is available to test. It's very simple.

ManickaP commented 2 years ago

Triage: let's investigate for 7.0 and root cause this then we can decide what to do about it.

rzikm commented 2 years ago

This does not look like .NET Runtime bug, the error comes from MsQuic.

I was able to reproduce this even outside MsQuic using the sample app from https://docs.microsoft.com/en-us/windows/win32/winsock/sio-acquire-port-reservation, the problematic range seems to be ports 50000-50059.

I filed issue with MsQuic to see if they can do something about it: https://github.com/microsoft/msquic/issues/2891

rzikm commented 2 years ago

There is something called Port Exclusion Ranges apparently that affects this:

> netsh int ip show excludedportrange protocol=udp

Protocol udp Port Exclusion Ranges

Start Port    End Port
----------    --------
     50000       50059     *
     55642       55741
     63552       63651

* - Administered port exclusions.
rzikm commented 2 years ago

Tracking by (internal) OS issue: https://microsoft.visualstudio.com/OS/_workitems/edit/40464377

karelz commented 2 years ago

Triage: There is nothing we can do. It needs to be address in the OS. Moving to Future for tracking purposes. If we see enough customers hitting it, we should document it properly.

ManickaP commented 1 year ago

This is documented in out troubleshooting guide.