Here, I explain what components are involved in DPF and how they interact each other. In a DPF connection setup and ongoing data communication, three entities are involved: a client, a server, a daemon called DPF inagent. The following picture shows the topology of DPF communication.
To enable inbound connections, each private (firewalled) network must have a DPF inagent installed on the firewall/NAT. Server applications that want to accept connections from outside their private (firewalled) network must use DPF socket calls. This can be done by rewriting/relinking the applications or by using an interposition mechanism so that applications' regular socket calls are translated into DPF calls. On the other hand, client applications need not be changed at all.
To be able to open firewall/NAT for a server socket, DPF inagent need to know what address the server socket is bound to as well as the fact that the socket is created. In addition, if the server socket is bound to a private address, it must lease a public address from the NAT box because private addresses are not routable outside their network. These are done by local binding, registration, and official binding. Uncomfortable with the term "lease"? Think about a NAT binding. When we have a NAT binding for a socket (no actually for an address), packets to/from the socket use a public address given by the NAT instead of the real (private) address. We say that the socket "leases" an address from the NAT.
Local binding is nothing new. As in bind of Berkeley socket, an (IP, port) pair called local address is assigned to a socket. Registration is simple too. Through the registration, the local address of the server socket is reported to DPF inagent so that the inagent can create a pinhole for the address.
Official binding is the process of assigning official address to the socket. Official address is the address that must be known to the application. That is, clients must call connect with server's official address. The server shall pass its official address to clients (See Review of socket API for how clients become aware of the server's address). If the server socket has a public local address, then the local address becomes the official address. However, if it is bound to a private address, then the address leased from NAT becomes the official address. In this case the server socket has different local and official addresses.
The following picture shows the timeline of how a pinhole is created through the local binding, registration, and official binding.The rightmost column shows socket calls that the server application calls. Two columns in the middle show what happen in the DPF layer of the server and DPF inagent, respectively.
When the application calls socket, DPF layer creates a socket as requested and records that the socket is a DPF socket.
The application calls bind, then DPF layer binds the socket to an (IP, port) pair by calling bind with the same argument--'addr-1' in this case. At this point, we say the socket is locally bound to 'addr-2'. Note that 'addr-1' and 'addr-2' can be different if the application calls bind with unspecified IP and/or port. The important thing to note is that 'addr-1' must not have a private IP address. When the application sees that a bind call with a specific IP succeed, it knows that the socket is bound to that IP. This means that the IP is a part of the official address. Since the IP part of the official address is determined by the application, DPF has no freedom to assign the official address with the address leased from DPF inagent. Therefore, if the machine has only public IP addres(es), applications must call bind with unspecified IP, i.e., INADDR_ANY. When bind is called with a private IP, then DPF gives up and treats the socket as non-DPF socket.
As the next step, DPF layer makes a TCP connection to DPF inagent and sends a BIND command with 'addr-1' and 'addr-2' through this connection. This management connection is maintained open only during the local binding ~ official binding period. All the other DPF commands such as heartbeats and DELETE commands are exchanged via UDP.
Upon accepting a new connection and receiving a BIND request, DPF inagent does the followings. As noted, the first step is done only when DPF inagent is managing a private network.
- Assign a public address--'addr-3' in the picture--to create a NAT binding at this address later. If the port of 'addr-1' is specified, 'addr-3' has the same port. In this way, DPF supports well-known services.
- Record necessary information about the socket, including local address, official address, the status, etc.
- Reply the result by sending BIND_OK with the official address or BIND_NAK with an error code.
When the application calls listen and then DPF layer sends LISTEN command, the inagent creates a pinhole or NAT-binding for the listening socket. and replies LISTEN_OK.
When the application calls getsockname to learn what (IP, port) the socket is bound to, DPF layer returns the official address instead of the local address that the socket is actually bound to. Note that the local address is hidden from the application and only the official address is known to it.
Once a pinhole or NAT-binding is created by the DPF inagent, DPF layer periodically sends HEARTBEAT commands to notify the inagent that the pinhole/NAT-binding must keep open. When the application calls close for the server socket, DPF layer sends DEL command so that DPF inagent can close opening for the socket. As explained earlier, HEARTBEAT and DEL commands are exchanged by UDP.
Once a pinhole/NAT-binding is created for a server socket, clients can talk to the server through the opening. One little complexity occurrs when both the server and the client are inside the same private network. In this case the server has different official address, which is a public address borrowed from the NAT box, from the local address. Note that the leased address is actually for clients outside server's network. If clients in the same network send packets to the official address, they may not be routed to the address. Even if packets are routed to the official address, they may take unnecessary detour and address translation--from client to NAT's public interface and then the destination gets translated to the local address of the server and finally to the server. What about reply packets from the server? Reply packets will be directly delivered to the client, thus bypassing NAT. What happen when the client sees reply packets from the address that it has never send packets to? To solve this problem, DPF uses a special mechanism for intra communication.
When the DPFnized application calls connect, DPF layer searches DPF routing table, which basically tells whether DPF mechanism should be used or not to connect to a specific address. If DPF mechanism must be used, DPF layer sends CONNECT request to the DPF inagent with the server's (official) address. Then DPF inagent replies the DPF layer ACTIVE with the local address of the server socket, meaning that the client can directly connect to the local address since it is in the same network. Then the DPF layer connects the socket to the address and returns the result to the client application.
Though everything so far has been explained for TCP, almost same things happen for UDP communications. I don't think it deserves any explanation.