13

My understanding of TCP connection is that a source PORT remains exclusive to one connection, no matter the destination is, so the number of connections from local port 12345 for example can never exceed 1.

I recently read that a TCP connection is identified by <src IP, src PORT, dst IP, dst PORT>

TCP allows source port sharing across multiple processes, but each process requires a free port to bind to for its connection

so I went to validate that "port sharing across processes": this must mean that the same source port can be used to connect to different destinations.

However, when experimenting this, I tried these two commands:

nc -v -p 12345 google.com 80

which works well (-v for verbose, and -p to specify the source port as 12345, for my learning purpose)

Now, simultaneously running this command on a different shell

nc -v -p 12345 github.com 80

fails with this error message:

nc: connectx to github.com port 80 (tcp) failed: Address already in use

the reason I specified the same source port with -p is to validate that a source port can be shared. There's no need for this practically, in real-world scenario I would not even worry about source port. According to this, is it true that a source port will be only used once?

1
  • 1
    Another (at least) Linux oddity is as a normal user you can bind to every ephemeral port over UDP and TCP providing you have enough file descriptors and finish the connect. This denies every other user network connectivity. A standard netstat or ss wont reveal what happened, but lsof implicitly shows the problem. Commented Jun 13 at 9:06

4 Answers 4

15

There is no reason why two processes cannot use the same source port, as long as they do not both connect to the same destination (host, port). On many UNIX systems, set the SO_REUSEPORT option to enable processes to share a port number; on Windows, set SO_REUSEADDR. For example, with socat:

  • process 1: socat stdio tcp:google.com:80,bind=:12345,reuseport
  • process 2: socat stdio tcp:bing.com:80,bind=:12345,reuseport

These two processes can run simultaneously, and will both have source port 12345 (as you can confirm with netstat).

Note, however, that you will almost certainly run into issues if the sockets are not closed cleanly on both ends, as unclosed TCP sockets will enter a TIME_WAIT state which will cause the four-tuple (srcaddr, srcport, dstaddr, dstport) to be tied up until the wait period expires. Therefore, when using a single source port for multiple connections, you cannot reconnect to the exact same server & port unless the previous connection has fully shut down or the TIME_WAIT period has expired.

7
  • 1
    There are other gotchas with this behaviour when connecting out, such as the same UID needs to be used for all connects. Also SO_REUSEPORT is not a default option and has to be enabled on every socket. Commented Jun 13 at 9:03
  • 3
    The same UID has to be used to create & bind the sockets, yes. If you want to get really fancy, you can send the bound sockets over to some other process via SCM_RIGHTS or via fork inheritance, to enable processes with distinct UIDs to connect using the same bound sockets. Of course, you would have to have a really good reason for doing such a crazy thing...
    – nneonneo
    Commented Jun 13 at 10:08
  • 2
    @Barmar: just try my code, it works on Linux and Mac at least (which is what I have access to). SO_REUSEPORT absolutely works with TCP sockets.
    – nneonneo
    Commented Jun 14 at 2:09
  • 1
    I guess it's evolved since I was doing network programming. I remember when the main use of it was so you could have multiple processes listening on the same multicast port.
    – Barmar
    Commented Jun 14 at 2:10
  • 1
    The socket(7) manpage linked in my answer explicitly points out load-balancing as one use-case for REUSEPORT on TCP sockets. Linux even provides SO_ATTACH_REUSEPORT_EBPF to customize exactly how incoming connections are assigned to listening sockets. However, the use-cases for reusing source ports are much more narrow, even if it is doable.
    – nneonneo
    Commented Jun 14 at 5:37
7

Any port is only ever allocated to a single process at any point in time. That process can create any number of connections with it, with the restriction that the destination IP address or port number must vary between connections.

As an example, TCP 10.0.0.10:49152 can connect only once to TCP 10.0.0.2:80 but can at the same time connect to TCP 10.0.0.3:80 or TCP 10.0.0.2:8080.

7
  • 8
    This is just not true on any major platform (at least Windows and UNIX/Linux). Processes can absolutely share ports; on Windows, set SO_REUSEADDR on subsequent binds to the same port, and on Linux/UNIX, set SO_REUSEPORT on every bind to the same port. It is only the default behaviour in which a port is allocated to a specific process.
    – nneonneo
    Commented Jun 13 at 8:47
  • SO_REUSEADDR can be used to quickly reopen a port just closed or in closing, but it cannot be used to share a port between arbitrary processes.
    – Zac67
    Commented Jun 13 at 9:35
  • 2
    You can just pass a socket between processes and thus any numbers of processes can share a port this way and create new connections. There is nothing in modern unix systems (and prtobably older ones, too) that would somehow associate a port with a specific process only. Commented Jun 13 at 18:34
  • 2
    A correct answer should point out that TCP only limits the number of 4-tuples (2x address, 2x port) to one, and that both sides of a connection are simultenously source and destination ports, as TCP/IP has no fixed client/server roles. Commented Jun 13 at 18:36
  • 3
    This answer would benefit from mentioning which OSes it applies on. Right now, it reads as if this non-sharing would be some natural property of TCP (or UDP), while I don't think the networking standards specify OS-level things like processes at all. Of course the OS has to figure out where to make the data available in userland, but I think on most systems, network connections are tied to sockets or other such handles, and not to processes directly (esp. since a process can often handle more than one connection at the same time).
    – ilkkachu
    Commented Jun 14 at 8:10
2

While the TCP protocol itself allows arbitrary combinations of local and remote ports and addresses, most Unix implementations simplify port management. The reason is that the process of setting up sockets is split into separate steps.

  • First you set the local port with bind(). This step is required when creating a listening TCP socket (you have to specify what port it's listening on), it's optional before making an outgoing connection with connect() (an arbitrary local port will be assigned). Since we don't know the remote address or port yet, it's not possible to tell whether this is fully unique. So it simply checks whether the requested port is available. If the socket has the SO_REUSEADDR option set, it ignores connected sockets when checking whether the local address is in use, but it will still fail if there's a listening socket on the port.

  • Then for an outgoing connection you call connect(), specifying the remote address. You can only call connect() once on a socket, and because we checked the local port during bind(), this can never produce a duplicate local/remote address/port.

  • For an incoming connection, you call accept() on the listening socket. Again, because we check that the local port of the listening socket is unused when we bind it, there can never be a duplicate combination.

Delaying the port checks until we have the remote information would complicate error handling. The current design just checks for duplication in one place: bind().

2
  • 1
    Slight point of clarification: bind() is not necessary when creating a listening socket. If you don’t call bind before listen, or you call bind with a zero port, a random ephemeral port will be assigned (which can be retrieved with getsockname). This can be used, for example, to create a service when there is no guarantee of any specific port being available.
    – nneonneo
    Commented Jun 14 at 8:45
  • Good point, that's how the FTP data connection is usually created. But just as with connect(), the random port will be chosen so it doesn't conflict with any other local port in use, since you don't know yet what remote ports will connect to it.
    – Barmar
    Commented Jun 14 at 13:44
1

After some investigations I found that source port sharing is only allowed for multiple outgoing connections from the same process. The operating system needs to know which process to forward the connection stream to.

Going to select this answer in two days as the site policy.

3
  • 5
    This is a limitation of the particular network stack (embedded in the Linux kernel) and not the tcp/ip protocol in general. You can pretty much share a source port even in Linux by using some iptables nat trickery.
    – fraxinus
    Commented Jun 13 at 5:27
  • 3
    This is not accurate. What you are describing is a traditional model, such as for outgoing SMTP connections. TCP port sharing is platform dependent and implementation dependent. For example, .NET has an implementation of it.
    – Greg Askew
    Commented Jun 13 at 11:08
  • 3
    "Going to select this answer in two days as the site policy." The delay isn’t just there to inconvenience you but to give time for other answers that you haven’t considered to come in. Notably, this answer is completely wrong, both in the described status quo and justification! Please select a correct answer instead! Commented Jun 13 at 16:42

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .