Jeremy Davis
Jeremy Davis
Sitecore, C# and web development
Article printed from: https://blog.jermdavis.dev/posts/2021/why-do-i-have-forbidden-sockets

Why do I have forbidden sockets?

Published 15 February 2021
C# ~1 min. read

I was tinkering with some C# code that uses

TcpListener
TcpListeners recently, and hit on a strange issue where my code would run fine on on machine, and fail on another. It took me a while to find an answer in Google, so here's a reminder to my future self:

The initial issue url copied!

In amongst the code I was running was a fragment like this:
_listener = new TcpListener(IPAddress.Loopback, 1234);
_listener.Start();
_listener = new TcpListener(IPAddress.Loopback, 1234); _listener.Start();
_listener = new TcpListener(IPAddress.Loopback, 1234);
_listener.Start();

					

On my home laptop this ran fine, but on another computer it crashed with an unexpected exception:

Exception

For Google's benefit, the stack trace was:

Unhandled exception. System.Net.Sockets.SocketException (10013): An attempt was made to access a socket in a way forbidden by its access permissions.
at System.Net.Sockets.Socket.UpdateStatusAfterSocketErrorAndThrowException(SocketError error, String callerName)
at System.Net.Sockets.Socket.DoBind(EndPoint endPointSnapshot, SocketAddress socketAddress)
at System.Net.Sockets.Socket.Bind(EndPoint localEP)
at System.Net.Sockets.TcpListener.Start(Int32 backlog)
at System.Net.Sockets.TcpListener.Start()
at Channels.ConnectionListener.Start() in C:\Users\JDavis\Source\Repos\ChannelsExperiment\Channels\ConnectionListener.cs:line 24
at Channels.Wrapper.Start() in C:\Users\JDavis\Source\Repos\ChannelsExperiment\Channels\Wrapper.cs:line 24
at Channels.Program.Main(String[] args) in C:\Users\JDavis\Source\Repos\ChannelsExperiment\Channels\Program.cs:line 23
at Channels.Program.<Main>(String[] args)
Unhandled exception. System.Net.Sockets.SocketException (10013): An attempt was made to access a socket in a way forbidden by its access permissions. at System.Net.Sockets.Socket.UpdateStatusAfterSocketErrorAndThrowException(SocketError error, String callerName) at System.Net.Sockets.Socket.DoBind(EndPoint endPointSnapshot, SocketAddress socketAddress) at System.Net.Sockets.Socket.Bind(EndPoint localEP) at System.Net.Sockets.TcpListener.Start(Int32 backlog) at System.Net.Sockets.TcpListener.Start() at Channels.ConnectionListener.Start() in C:\Users\JDavis\Source\Repos\ChannelsExperiment\Channels\ConnectionListener.cs:line 24 at Channels.Wrapper.Start() in C:\Users\JDavis\Source\Repos\ChannelsExperiment\Channels\Wrapper.cs:line 24 at Channels.Program.Main(String[] args) in C:\Users\JDavis\Source\Repos\ChannelsExperiment\Channels\Program.cs:line 23 at Channels.Program.<Main>(String[] args)
Unhandled exception. System.Net.Sockets.SocketException (10013): An attempt was made to access a socket in a way forbidden by its access permissions.
   at System.Net.Sockets.Socket.UpdateStatusAfterSocketErrorAndThrowException(SocketError error, String callerName)
   at System.Net.Sockets.Socket.DoBind(EndPoint endPointSnapshot, SocketAddress socketAddress)
   at System.Net.Sockets.Socket.Bind(EndPoint localEP)
   at System.Net.Sockets.TcpListener.Start(Int32 backlog)
   at System.Net.Sockets.TcpListener.Start()
   at Channels.ConnectionListener.Start() in C:\Users\JDavis\Source\Repos\ChannelsExperiment\Channels\ConnectionListener.cs:line 24
   at Channels.Wrapper.Start() in C:\Users\JDavis\Source\Repos\ChannelsExperiment\Channels\Wrapper.cs:line 24
   at Channels.Program.Main(String[] args) in C:\Users\JDavis\Source\Repos\ChannelsExperiment\Channels\Program.cs:line 23
   at Channels.Program.<Main>(String[] args)

					

My initial thought was "ah, there'll be something else using that port..." but running

netstat -ano
netstat -ano didn't show a hit against the loopback address I was trying to bind:

Active Connections
Proto Local Address Foreign Address State PID
TCP 127.0.0.1:1029 127.0.0.1:1030 ESTABLISHED 5604
TCP 127.0.0.1:1030 127.0.0.1:1029 ESTABLISHED 5604
TCP 127.0.0.1:1715 127.0.0.1:1716 ESTABLISHED 5604
TCP 127.0.0.1:1716 127.0.0.1:1715 ESTABLISHED 5604
TCP 127.0.0.1:1763 127.0.0.1:62522 ESTABLISHED 10852
TCP 127.0.0.1:62522 127.0.0.1:1763 ESTABLISHED 4780
Active Connections Proto Local Address Foreign Address State PID TCP 127.0.0.1:1029 127.0.0.1:1030 ESTABLISHED 5604 TCP 127.0.0.1:1030 127.0.0.1:1029 ESTABLISHED 5604 TCP 127.0.0.1:1715 127.0.0.1:1716 ESTABLISHED 5604 TCP 127.0.0.1:1716 127.0.0.1:1715 ESTABLISHED 5604 TCP 127.0.0.1:1763 127.0.0.1:62522 ESTABLISHED 10852 TCP 127.0.0.1:62522 127.0.0.1:1763 ESTABLISHED 4780
Active Connections
  Proto  Local Address          Foreign Address        State           PID
  TCP    127.0.0.1:1029         127.0.0.1:1030         ESTABLISHED     5604
  TCP    127.0.0.1:1030         127.0.0.1:1029         ESTABLISHED     5604
  TCP    127.0.0.1:1715         127.0.0.1:1716         ESTABLISHED     5604
  TCP    127.0.0.1:1716         127.0.0.1:1715         ESTABLISHED     5604
  TCP    127.0.0.1:1763         127.0.0.1:62522        ESTABLISHED     10852
  TCP    127.0.0.1:62522        127.0.0.1:1763         ESTABLISHED     4780

					

(I checked against the real IP address of the machine as well – nothing there either)

So I fell back on "it was a security error – maybe I have fewer rights on this machine?" and tried running Visual Studio (and also my test app) as admin. But no difference there either.

The answer... url copied!

After a pile of futher googling I hit upon an idea that was entirely new to me. It turns out code can reserve a port, without ever actually opening it. That means Windows will refuse you rights to use it for anything else – but it won't show up on the netstat call shown above. And the refusal comes up as the odd security error above.

To work this out you need a different command:

netsh interface ipv4 show excludedportrange protocol=tcp
netsh interface ipv4 show excludedportrange protocol=tcp and for me that gives:

Protocol tcp Port Exclusion Ranges
Start Port End Port
---------- --------
1132 1231
1232 1331
1435 1534
1555 1654
1819 1918
50000 50059 *
* - Administered port exclusions.
Protocol tcp Port Exclusion Ranges Start Port End Port ---------- -------- 1132 1231 1232 1331 1435 1534 1555 1654 1819 1918 50000 50059 * * - Administered port exclusions.
Protocol tcp Port Exclusion Ranges

Start Port    End Port
----------    --------
      1132        1231
      1232        1331
      1435        1534
      1555        1654
      1819        1918
     50000       50059     *

* - Administered port exclusions.

					

My code tried to open port 1234, and that is included in the second of these ranges... Bingo!

The critical info here came from this Stack Overflow answer, if you want to read the original source.

So I can use this info to pick a port that's free on all my machines, and my little bit of test code can run happily.

↑ Back to top