The source of the problem is the source port, which is a random number that only signifies what application running on a source host is requesting one particular connection. And it has to be a random number, because if it isn't it's a security issue. And re-use of ports is only necessary because we're using this finite range of numbers to signify a unique connection.

The deeper down the rabbit hole you go, the more you realize that little of modern connections are by design, but rather are built on a series of kludges used to fix problems and use-cases that the original design didn't cover.

A modern network stack could bring a lot of benefits. Here's a few things I would like in a new stack:

- Service discovery. The reason nothing on the internet can use any port other than "443" is that we failed to build in the ability for TCP to relate to services rather than applications. TCP/443 refers to the application-layer of "HTTP", but also the transport-and-application layer of "TLS". And one IP can only ever host a single application on that host and port. If you want to run multiple applications, you have to run one application which talks the application protocol, deciphers what host you want from TLS, deciphers what host you want again from HTTP, and then opens up another connection to get you to the actual service you wanted. This is convoluted and unreliable - and decrypts the payload far from the actual application that should be looking at this data! Instead, the protocol's destination should be a combination of identifiers, and the stack should route the connection to the appropriate application. For example, instead of "host node01/port 443", you could open a connection to "host:node01/protocol:tls/protocol:http/service:public-web-pool-hackernews" (not that verbose though). All the application needs to do is open a listening socket with the same connection string, and the operating system will look up the application matching that connection string, unbundle any protocol layers it can, and connect a new file descriptor to the waiting application. You could even have multiple applications open listening sockets on the same connection string and the OS could round-robin connections to them automatically. And routers could pass connections to services distributed on pools of hosts without the need for an "application-specific load-balancing reverse-proxy". We can run all kinds of layers of protocols and services, and there is no limitation of tying up a single integer "443" with all these different concepts. This also allows us to expand the number of real internet protocols and not just keep stacking crap on top of HTTPS because we can't route any other traffic because everyone's hard-coded themselves into this one port number.

- TLS becomes a part of the ABI. Any network application that wants to use TLS could open_tls_connection() and get a file descriptor. Just like applications shouldn't have to implement their own TCP/UDP packet parsers, they shouldn't have to bundle their own TLS implementations. This simplifies application code and increases speed by letting the kernel unbundle the payload from the encrypted session.

- With the above two changes, add authentication and authorization layers to the stack. Now any network service can have encryption, privacy, authentication, and authorization, without needing every application to explicitly build in support for a particular method. This would allow you to write some arbitrary web app that requires login, and add an implicit trust of authorizations from host "github.com" with realm "public". If you get a connection request that's signed properly, you know the user is an authorized github.com user (and a payload with their metadata). Imagine authenticating every single network call by default. This would make it dead-simple to secure all network endpoints that often get left exposed on the internet with no authentication.

- Distributed Tracing tags should be added to every layer and hop of a connection, the way an IP TTL is passed. This way you could know exactly where a connection is failing anywhere along its path. You could also pass tags forward along new connections to explicitly carry forward a trace, such as a database connection carrying a tag from a previous HTTP connection. No need for "DT infrastructure", every OS's stack would just come with tracing bundled and you could ls /proc/net/* to find out what was related to what.