The Demultiplexing Principle

Just as a kernel is responsible for isolating programs from one another, protecting each program‘s memory, CPU budget, etc from interference by other programs, a network stack is responsible for isolating programs’ network resources, protecting them from interference by other programs.

More generally, we can say that a network stack is responsible for isolating the resources of different security domains, where a security domain might be a process, a collection of processes (for example, a collection of processes owned by the same user on a UNIX system), a sandbox within a process (for example, a web assembly program run inside of a VM which runs multiple such programs at a time), etc.

Isolation of network resources is a security property. Imagine a security domain, A, that initiates a TCP connection with a remote server, and accepts instructions over that connection. If another domain, B, on the system is able to inject data into the TCP stream, then an important security property of domain A has been violated.

Since all interaction with the network stack (excepting management plane interaction, which is not relevant to this discussion) is via sockets, this implies that the stack is responsible for isolating sockets from each other. A given security domain may opt to allow two or more of its sockets to interfere with each other since that doesn‘t violate that domain’s security, but this must not be the default, at least for sockets owned by different domains.

We define “interference” here as one socket either receiving traffic that was meant for another one, or causing traffic that should be received by it to be received by a different socket instead. In other words, when a remote host receives a packet and then responds with a packet of its own, it intends for the response to be received by the original sender. Conversely, when a remote host sends a packet unprompted, it intends for that packet not to appear as though it is the response to some previously-sent packet. A socket has “interfered” with another socket if either of these properties don't hold.

Outbound traffic from multiple sockets is multiplexed together into a single outbound stream of IP packets or link-layer frames. Inbound traffic - in the form of a single stream of IP packets or link-layer frames - is demultiplexed in order to deliver each packet to the appropriate socket. Different sockets may employ different demultiplexing schemes (for example, TCP and UDP use the four-tuple of remote and local IP address and remote and local port, while ICMP echoes use the three-tuple of remote and local IP address and ICMP ID), but the fundamental requirement of being able to demultiplex a single stream of inbound traffic into multiple different sockets remains the same.

Together, these security requirements and the multiplexed nature of network traffic imply what we refer to as the demultiplexing principle. The demultiplexing principle states:

1. Every socket is associated with a set of packet addresses such that it
   would be valid for the socket to receive a packet with any of the
   addresses in that set. This is called the socket's "address set".
2. No two sockets may exist at the same time whose address sets overlap.
3. A socket must never send a packet that would prompt a response whose
   address is not in the socket's address set.

If two sockets, A and B, are owned by the same security domain, then the
rules are relaxed as follows:
4. Sockets A and B may exist at the same time even if their address sets
   overlap so long as the owning security domain has opted into it.

Note that (3) depends on the semantics of the protocol in question.

If we follow rules (1) through (3), then we can guarantee two things. First, we can guarantee that it can never be ambiguous which socket to deliver a packet to (if it were ambiguous, it would imply that rule (2) had been broken). Second, we can guarantee that, given sockets A and B, socket A can never interfere with soket B by sending traffic whose response will be delivered to socket B (if it could, this would imply either that the response traffic could be delivered to either A or B, violating rule (2), or that the traffic was unambiguously destined to socket B, violating rule (3)).

Consider what might happen if we don‘t abide by this principle. We might have two UDP sockets - socket A with local address 1.1.1.1:1234 and remote address *:*, and socket B with local address 1.1.1.1:1234 and remote address 2.2.2.2:5678. If an inbound packet is received from 2.2.2.2:5678 to 1.1.1.1:1234, which socket should it be delivered to? It’s possible that the remote host is attempting to communicate with socket A. It‘s also possible that socket B previously sent a packet, and the remote host is responding to it. There’s no way to tell which is the case, and so it's ambiguous which socket should receive the packet.