The SO_REUSEADDR option has quite different functionality on Windows than it does on Unix.
Anybody who’s done more than a little work at the sockets layer will have
encountered the SO_REUSEADDR
socket option. For anybody who hasn’t, first a
little background: when a TCP socket is closed, it’s kept lingering around
for a little while in a state called TIME_WAIT
. This is essentially a
safeguard to prevent the port number being reused for another service until
there can be a fair degree of confidence that there aren’t any outdated packets
from the connection bouncing around that might get erroneously delivered to the
new service, royally confusing everyone.
This option is great for client sockets because the number of outgoing ports is huge enough that typically it’s not a big deal having some sockets kicking around the place (it can cause issues on extremely busy systems that are making connections at a rapid rate, but we’ll gloss over that). It’s a bit more annoying for servers which listen for connections, however, since they typically need to re-acquire the same port number when they get restarted.
To work around this issue, the SO_REUSEADDR
socket option was created which
allows the port number to be reused by a new socket immediately. On Unix
systems this means that if the old socket is in TIME_WAIT
(and perhaps some
of the other idle states) then a new socket can come along and steal the port
number. Since the TIME_WAIT
state is really just a precaution then this is
generally pretty safe.
So far I’ve been discussing the behaviour of this option on Unix systems, but the same option also exists on Windows. However, I recently discovered that its operation is actually quite different. Instead of allowing a socket to “steal” the port number from an inactive previous one, it actually allows a socket to “steal” the port from any other socket, including actively listening ones. This could be fine if one socket is UDP and the other TCP, for example, but Windows will happily allow two or more active TCP sockets to share port numbers.
This MSDN page explains how the option works under Windows — the upshot is that if two sockets end up sharing a port then the behaviour of an incoming connection is undefined. Helpful.
As the article goes on to point out, this is a bit of a security problem — you can have a trusted service listening on a particular port and some other piece of malware can come along and silently steal the port, intercepting all the connections — this is a brilliant opportunity for a man-in-the-middle attack (admittedly requiring the ability to run code on the server machine).
Microsoft’s solution to this was not to change the operation of SO_REUSEADDR
as you might expect, but to add a new option SO_EXCLUSIVEADDRUSE
which
explicitly prevents any other sockets listening on the same port, even if they
use SO_REUSEADDR
. Ah, why use one socket option when two will do?
Anyway, definitely something to bear in mind when writing Windows services (and, perhaps more importantly, when debugging them).