Fixed port range IP pools algorithm
This section explains how FortiOS selects IP addresses and ports when using Fixed Port Range IP pools.
In a Fixed Port Range type of IP pool there is nothing to force the internal and external ranges to be the same size so there isn't an obvious way to predict what the external IP address is going to be based on the internal or source address. There is no one-to-one relationship between the addresses.
Here's an example scenario for when you might want to use Fixed Port Range IP pool:
- Internal IP subnet of computers using an IP pool: 172.16.4.1 - 172.16.7.255. This means there are 1022 usable IP addresses.
- The company has what used to be called a C-class address which is 254 usable addresses on the Internet. Of these, 64 have been set aside for the IP pool.
While there isn't any obvious method of prediction, in some situations there can be a requirement to be able to predict the relationship between the source IP address and the one that it is given from the IP pool. This can occur in situations, that for security reasons, the public IP address of a session needs to be known because communications between sites are limited to specific IP addresses.
Determining the IP address from the pool
This section describes the logic used to determine the IP address.
Defining the variables
The first step in having the algorithm make sense is to define the variables:
Variable name |
Description |
---|---|
src_start | Starting IP address of the source IPs of the IP pool. |
src_end | End or last IP address of the source IPs of the IP pool. |
start | Starting IP of the translated IP addresses of the IP pool. |
end | End or last IP of the translated IP addresses of the IP pool. |
src_ip |
Incoming IP address from the source device. This will fall in the range src_start to src_end. |
The equations
To make the algorithm more manageable and understandable, it is broken into 2 parts.
Floating point calculations are not used, so the result from the factor calculation will be an integer. The value is truncated, not rounded, so 36/10=3, not 4, as would be the case if rounded to the nearest integer.
Setting values for the example
Because spanning multiple subnets makes the math trickier, the example uses a Fixed Port Range IP pool.
Variable | Value |
---|---|
Source (internal) range | 192.168.1.100 - 192.168.1.200 |
External range | 10.1.1.50 - 10.1.1.80 |
example source IP address | 160 |
First equation - determining the factor
Second equation - determining the IP address from the pool
If a computer with the IP address 192.168.1.160 initiates a session through a policy using the example IP pool, 10.1.1.65 will be assigned as the NATed address.
These calculations get more complicated when subnets are overlapped, but this example should give the basic principles behind the process for assigning IP addresses.
Determining the TCP ports
The TCP port being use in a session could also be used to help determine which computer is the originating source of the session, if it could be narrowed down far enough. This is more difficult than working with the IP addresses. The problem is that determining which ports are assigned can have less to do with a unique computer identity than the order in which the sessions were initiated.
Normally the scope of probable TCP ports is a larger range of numbers than the scope of IP addresses.
Defining the variables
Variable name | Description |
---|---|
snat_port_begin | The beginning of the range of NATed ports. |
snat_port_end | The end of the range of NATed ports. |
port_share | The range size that the total number of available ports will be divided into to distribute the ports among the sessions. |
first_port_choice | The number of the port that FortiOS will try to use first for the session. |
src_ip src_start factor |
These variables were all defined in the previous algorithm. |
Setting values for the example
Variable | Value |
---|---|
snat_port_begin | 5117 |
snat_port_end | 65533 |
These values are the default ones in the system. With an entire port range of possibilities from 5117 (snat_port_begin) to 65533 (snat_port_end), It makes for a large number of possibilities. It does get narrowed down a little by using the factor equation to divide the range into shares for the sessions to use.
The equations
This equation is used to divide the total number of available ports into port shares that are of equal size for the sessions to be divided between.
To determine the first choice of ports for a session, a second equation is used.
This equation make use of the MOD modulus function. The use of MOD involves multiplying by the remainder, instead of the resulting value from that portion of the equation. This has the effect of distributing the ports for session not like a continuous stream but more like dealing out cards from a deck. Session from IP address x goes to port share 1. Session from IP address x+1 goes to port share 2 and so on until FortiOS runs out of shares that it starts over from the beginning.
Using the information from the previous example, the calculations step by step look like this:
First equation - determining the port share
We know the factor is 4, so determining the port_share is straightforward.
Second equation - determining the first port choice for the session
Before running the whole second equation let's solve the MOD portion.
It happens in this case that 4 divides into 60 evenly with no remainder, making the value 0 and forcing us to multiply by 0. If the src_ip was 162, the remainder would have been 2.
To add a little ambiguity, the value produced by this equation does not guarantee that it will be the port used. Ports are assigned on a first come, first served basis. If the first_choice_port is being used by another session already, then FortiOS uses generic logic going up the port list incrementally, to search for the next available port.
This methodology in determining the port used for a session tries to strike a balance between assigning specific port numbers and making sure that every session can be assigned a port. Because some computers will generate a lot more sessions than others, a certain amount of flexibility has to be built in. With that flexibility comes unpredictability.
If the options for the port were limited to the scope of the port_share, one could expect the options for the ports assigned to sessions from the IP address in the example to be anywhere from 5117 to 20220. 20220 being the number before the first_port_choice in the next port share. If the remainder for the MOD portion of the equation been 1 instead of 0, the first_port_choice value would have been 20221. However, because FortiOS keeps going up the port list until it finds a free one, if for some reason all of the ports in the first range are already in use, FortiOS keeps going through the list until it finds a free port, even if it is a number above 20221.
The algorithm for assigning ports works very well for making sure that whenever possible, every attempted session gets a port for the purposes of NATing. The drawback is that, while it gives a probable port range, it doesn't guarantee the sessions will be within the range. This means that reversing the algorithm to determine the source computer for the purposes of forensic analysis will not give a definite conclusion.
For more information, see the Fortinet Knowledge Base article How FortiOS selects unused NAT ports.