Reserve a TCP port in Windows
Asked Answered
L

5

18

I'd like to reserve a TCP port, to be bound by a service later, so that Windows doesn't inadvertently use the same number when assigning random port numbers. I know this is possible via the registry and a reboot, but I would like to avoid such a heavy-handed solution.

How can a process reserve a port without actually binding/listening to it, and then safely (i.e., avoiding race-conditions) hand it over to another process on request?

The port number needn't be determined in advance. It's OK for the first process to acquire a random port number, and pass it to the requesting process.

EDIT: It occurs to me that my question is somewhat poorly stated. What I really want is to separate the allocation of a dynamic port number from the bind-to-port-zero operation. This means not just avoiding accidental random allocation of that port number, but also preventing any other process from binding to the same address/port in the interim. Or, putting it another way, I want one process to start the bind-to-port-zero operation — immediately learning the port number that will be used — and let a nominated second process complete the bind operation sometime in the future.

At the moment, the closest work-around I can think of is for the first process to bind to address/0 immediately, and stay bound until the second process requests it, at which point it unbinds and tells the other process the port number it acquired, which then binds to the address/port explicitly. This has two problems: 1) I'd rather not bind at all until the second process comes along; 2) there's a small time interval during which a third party could accidentally (or deliberately) usurp the port.

Background

You may be curious as to why I wish to do something so odd. I've been toying with ZeroMQ, and one major limitation is the absence of the ipc:// transport on Windows. It struck me that a port mapper process (akin to the RPC endpoint mapper, or Erlang's epmd) would be just the ticket to implement a work-around using the tcp:// transport with dynamic port allocations. However, ZeroMQ clients and servers are allowed to connect out of order (i.e., it isn't an error for the client to connect before the server binds), so I am trying to figure out how a connecting client can discover — with a very high degree of certainty — the port that will be used to communicate, before a server actually binds to that port.

Ladle answered 10/3, 2011 at 1:9 Comment(2)
Note that Windows does support something roughly equivalent to Unix sockets, it's called "Named Pipes" (both streaming and message/datagram-like modes are available). So the best solution is probably to implement "ipc:" on Win32.Equable
@BenVoigt thanks for the suggestion. Unfortunately the semantics of named pipes are different enough from sockets that most applications can't use them as a drop-in replacement.Ladle
S
14

As mentioned by @vahapt you can modify the dynamic port range using netsh.

However, a better solution may be to use netsh to reserve the ports required by your application, leaving alone the default range of dynamic ports.

To do so:

  1. On Server 2008/2008 R2, install this Microsoft hotfix. This is not required on Server 2012 or later.
  2. Stop any processes using the ports to be reserved. If a process is using a port included in the range of ports to be reserved, NETSH will return the following error and the reservation will fail:

    The process cannot access the file because it is being used by another process.

  3. Use the following NETSH command to reserve the ports:

    netsh int <ipv4|ipv6> Add excludedportrange [protocol=]tcp|udp [startport=]<integer> [numberofports=]<integer> [[store=]active|persistent]

    For example, to reserve ports 55368-55372 for UDPv6, use the command:

    netsh int ipv6 add excludedportrange protocol=udp startport=55368 numberofports=5

Notes:

  • By default port reservations are persistent across reboots
  • Ports may be reserved for either version 4 or 6 of a protocol, but not both (i.e. you cannot reserve port 60000 for both TCPv4 and TCPv6)

See https://support.microsoft.com/en-us/kb/929851 for more information, including how to view or delete existing port reservations.

Skinned answered 6/6, 2016 at 16:7 Comment(1)
To reverse any configuration use the delete command. For example if you did: netsh int ipv4 add excludedportrange protocol=tcp startport=44349 numberofports=50, use netsh int ipv4 delete excludedportrange protocol=tcp startport=44349 numberofports=50 to reverse it.Auk
A
6

Using netsh command might help you. You can change the dynamic port range used by Windows.
It is like the registry modification that you indicated, but it is effective immediately.

see: http://support.microsoft.com/kb/929851 for details about netsh command.

Arbuckle answered 10/3, 2011 at 1:27 Comment(1)
+1 for a good suggestion. It made me realise that don't even need to change the settings, just query the dynamic port range and choose port numbers that fall outside the range. I have, however, rethought (and edited) my question to more accurately reflect what I'm after, which isn't really helped by either knowing or manipulating the dynamic port range.Ladle
B
5

Edit: This only applies to pre-Windows Server 2008 (Microsoft Support KB)

You can edit the 'ReservedPorts' Registry Setting in

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters

To reserve a range of ports follow the format '4000-4010' or 'xxxx-yyyy' however to reserve a single port you have to use the format of '4000-4000' or 'xxxx-xxxx'

http://support.microsoft.com/kb/812873

Baroque answered 1/2, 2012 at 21:51 Comment(2)
Thank you for taking the time answer, but I don't want to fiddle the registry.Ladle
This works for Server 2003 but the ReservedPorts registry setting was removed in Server 2008 onward.Skinned
L
2

I've come up with a possible solution, so I thought I may as well document it here as an answer.

A process can pass a socket over to another process via a call to WSADuplicateSocket, so a coordinating process could bind to a dynamic port, and internally associate it with a given IPC name. When a ZMQ server process wanting to "bind" to that name arrives, the coordinating process copies the bound socket to the server process and closes its own copy.

This solution doesn't address my preference to avoid calling bind(), but that may not be strictly necessary; I'll have to perform some tests.

Ladle answered 15/3, 2011 at 1:37 Comment(0)
T
0

For ZeromMQ, you can use the zbeacon module from czmq or C# NetMq to implement service discovery.

Transpose answered 13/3, 2015 at 14:25 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.