Sunday, April 4, 2010

Reusing Ports: Socket Option SO_REUSEADDR

Recently, I came across a situation where I had to bind the same port to multiple sockets. I am just going to write some brief notes about this.

Is it possible to bind multiple sockets to the same port?
Yes, it is possible.

How?
There is a socket option for this, called SO_REUSEADDR.

Why would someone want to reuse a port?
This option is sometimes needed. For example,
  1. Suppose you have restriction on the number of ports you can use. Then you may want to use the same port for connecting to different destinations.
  2. The original use case for this option occurs when a socket is closed. It may "linger" for a while, because there is still unsent data in the buffer. So you cannot use (bind to) that port right away after the socket is closed. So you can set SO_REUSEADDR on that socket, if you think the port needs to be usable right away after closing a previously bound socket.

Can I prevent a port from being reused or hijacked?
Yes, you can.
In Linux, if you do not set SO_REUSEADDR on a socket, the port bound to that socket cannot be rebound by another socket.
But in Windows, even if you do not set SO_REUSEADDR, that port can be bound to another socket if the second socket sets SO_REUSEADDR before bind!
In order to prevent this, Windows provides another option called SO_EXCLUSIVEADDRUSE. When this option is set on a socket, the port bound to that socket cannot be reused by another socket.

Example problem
I would like to bind any free port to socket S1. Then I would like to bind that specific port to socket S2 as well.

Solution
  1. Bind any free port to S1 (specifying zero for port does this).
  2. Set socket option SO_REUSEADDR to S1 (Do not set this before binding, so that an unused port is guaranteed to be bound to S1 in step 1).
  3. Find out the port number P that is bound to S1 (getsockname can be used for this).
  4. Set socket option SO_REUSEADDR to S2 (Some OS may not need this step. But it does not do any harm to do it anyway).
  5. Bind the specific port P to socket S2.

No comments: