I am trying to make my ASP.NET Core (.NET 6.0) application bind to a fixed port that is 49913
. I have set this up using the launchSettings.json
(for debugging) and appsettings.json
(for release) as well:
launchSettings.json:
{
"profiles": {
"Controller": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": false,
"applicationUrl": "https://[::1]:49913",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}
appsettings.json:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"Kestrel": {
"EndpointDefaults": {
"Protocols": "Http2"
},
"Endpoints": {
"Https": {
"Url": "https://[::1]:49913"
}
}
}
}
But when I try to start the application, I'm getting a SocketException
with error code 10013
(access denied). But I don't understand what's denying the access.
netstat -aon
does not list this port (or any of the 499XX range) as in-useI tried a different port (namely 59913), just to see what would happen, and it works fine. Then I tried 49910, and it failed again with the same error (10013
access denied).
What's different about 49913 & Co. to make it fail? What can I do to find out what's up with that particular port range?
With the help of some links in the comments I was able to figure it out.
Various different bits of the question and answers here suggest the problem is related to some virtualization feature of Windows, namely HyperV (which is used for the Windows Sandbox for example) or WSL.
The problem appears to be that these features use NAT, utilizing the winnat
service. This service reserves some port ranges for the NAT usage, apparently in blocks of 100 consecutive ports.
One can verify that using the command netsh int ipv4 show excludedportrange protocol=tcp
in a regular cmd shell (no elevation needed). This is what the output might look like (translated from German, numbers are faked example values):
Excluded port ranges for the protocol "tcp"
Start port End port
---------- --------
1453 1453
5357 5357
6900 6900
7564 7564
50000 50059 *
54267 54366
54467 54566
54869 54968
55069 55168
59013 59112
59113 59212
59230 59329
59330 59429
59696 59795
59796 59895
59896 59995
59996 60095
62249 62348
62349 62448
62449 62548
* - Managed port exclusions.
By the looks of it, this list grows over time; frankly, I'm not sure if that's a technical necessity I am failing to understand, or a "resource leak" (where the "resource" are port reservations). Anyway, some answers suggest that restarting the winnat
service fixed their problem, like so (elevated shell required):
net stop winnat
net start winnat
Doing so will release most of the reserved ports back to the pool. If there is some program that needs a specific port (Docker for example), then you can start that in between those two commands, and it should work.
However, restarting winnat
comes at a "cost": afterwards, programs like Windows Sandbox cannot connect to the Internet any longer, even if you [re]started those programs after the restart of winnat
. To fix this, you need to reboot your computer. Beware however that this will mean winnat
will reserve some blocks again, albeit probably different ones than before.
Obviously, this is just a short term solution. Without further actions taken, any particular port may by chance end up in a range of reserved ports again at some point in the future.
To make sure this doesn't happen and the desired port remains free to use in the future, you can reserve that port (or a port range) yourself using these commands (elevated shell required):
netsh int ipv4 add excludedportrange protocol=tcp startport=49913 numberofports=1
(only reserve 49913
)
netsh int ipv4 add excludedportrange protocol=tcp startport=49900 numberofports=100
(reserves the whole range 49900-49999
)
This will mean these ports are reserved, but not used. Despite them being reserved, your program can still bind to them.
In case it's needed, using delete
instead of add
removes an excluded port range again from that list. The newly added range will appear as "Managed port exclusion" (with a *
behind it).
If you looked up the excluded port ranges and it did not list a range that included your desired but blocked port, then there might be a problem with the setting which ports can be bound to.
The dynamic port range wasn't always the range it is today, and to adapt to the latest change, Windows adjusted/updated the rules for its dynamic port range some time back. Some users however claimed that this automatic update hadn't worked for them, so they needed to manually adjust it. You can check what the configured dynamic port range is on your system using this command:
netsh int ipv4 show dynamic protocol=tcp
(no elevation needed)
A correct example output looks like this:
Protocol tcp Dynamic Port Range
---------------------------------
Start Port : 49152
Number of Ports : 16384
If that doesn't match your output, it may still look like this:
Protocol tcp Dynamic Port Range
---------------------------------
Start Port : 1024
Number of Ports : 64511
You can use this command to fix it (elevated shell required):
netsh int ipv4 set dynamic tcp start=49152 num=16384