Matches-based NAT
In Linux, NAT is based on match, that is, to execute SNAT or DNAT when a series of conditions are met, so the requirement is loose. The only constraint is routing, that is, when a routing action occurs, it must be based on the final destination IP address, so DNAT must occur before the route (for packets sent from the local machine, after the route, and then re-route), as shown in
Appendix: Netfilter and ip_conntrack
Netfilter
The Linux protocol stack only implements basic protocol operations. Corresponding to TCP/IP standards, the Linux protocol stack only implements a minimal set. Almost all other extensions (not all! Net schedule) is implemented by Netfilter, including IP Firewall, ip nat, IPSec, and IPVS.
Ip_conntrack
Ip_conntrack is the top priority of NAT implementation. Linux NAT relies entirely on ip_conntrack and on ip_conntrack.
Basic Data Structure:
It is worth noting that the quintuple nodes in both directions are stored in a hash table after confirm, and they are not treated differently, if you use a quintuple as the key to find the quintuple node in any direction, you can find the ip_conntrack struct itself. In addition to quintuple information, quintuple nodes also contain direction information.
How does NAT process attach to ip_conntrack? As shown in, NAT modifies the reverse quintuple in ip_conntrack, but does not affect the positive quintuple, this feature allows you to use a very clever method when implementing NAT in Linux.
The NAT process is as follows:
Note: Since only the first packet of a stream will create an ip_conntrack struct, the first packet will match the NAT rule configured with ipptables. This is a limitation.
In the early kernel of 2.6, NAT data, including the IP address to be converted, and other data are stored in the extension of CT, which is called ip_nat_info, the info can be obtained from CT, and the ip_nat_info_manip in it is used as the basis for NAT when NAT is executed when nf_nat_fn is reached. However, in later versions, a more efficient method is used. The IP address to be converted is not stored in ip_nat_info, but directly obtained by using the calculation method in the preceding flowchart, that is, obtain the reverse quintuple, obtain the inverse, and execute the result. There is a basis for doing so, because after the NAT rule is successfully matched, The tuple in the reverse direction is directly modified, because the NAT rule is successfully matched to the forward direction of the quintuple, after all, only the first packet will match the NAT rule. How can this problem be solved? Therefore, since the NAT rule is modified in the inverse direction of the quintuple, after the standard is obtained, it is the positive direction of the quintuple after NAT. In this process, the quintuple in the square direction remains unchanged! For the back-to-back packet, the reverse direction is the positive direction. Since the positive direction has never been changed, the reverse direction becomes the original back-to-back quintuple, the quintuple of the returned package can be restored! Because of this, Linux NAT is so sensitive to the direction: the packet that matches the rule in the positive direction is changed to the quintuple in the opposite direction! Note that forward, forward, and reverse directions are not the same. forward and reverse directions are for the current direction, the forward and backward directions are for the direction from the initiator of the data stream to the receiver.
From this implementation, we can see the development of Linux kernel. in earlier versions of 2.6, after successful NAT rule matching, we also modified the back-to-back quintuple, but why didn't reverse quintuple get inverse as the basis for address conversion? In fact, this can be done at that time! Facts have proved that the Linux kernel is full of techniques that are gradually recognized and discovered. This also reflects the "90% feature" of network community development, that is, even 90% availability, without 100% perfection.