Implement a two-way Nat virtual network card

Source: Internet
Author: User
Problem description and Solution

In Linux, Nat configured through iptables cannot be used in a two-way communication environment. You cannot configure a NAT rule to perform nat on traffic actively initiated in both directions, there are several solutions to this problem:

1. Configure two Nat rules

The NAT configuration of iptables is to match and then execute a target. Therefore, a rule can only represent one conversion policy. To achieve "conversion from the source address of data packets from X to Y, to convert the target address of the data packet destined for y to X, two rules must be used. So why not use the two rules? Because the NAT configuration of iptables is based on data streams, it only performs rule searches for the packet that creates the ip_conntrack struct. Therefore, when a stream has been created and data transmission is performed, adding a NAT configuration is invalid.
Xtables-Addons has a rawnat, which is no longer based on ip_conntrack, that is, it is based on data packets rather than data stream Nat. The problem is solved immediately, but because it is still a match-target rule, therefore, to implement bidirectional Nat, you must configure two rules.

2. Compile a netfilter hook

Writing a netfilter hook module is not difficult. I have written several articles by myself. However, the netfilter framework intercepts data packets in the protocol stack processing path for checking-matching/action, it checks each data packet that passes through the Protocol Stack. That is to say, each data packet must be filtered by the hook function. When there are too many netfilter hooks, the efficiency is greatly reduced.

3. Use dedicated Virtual Devices

This is a brand new concept. The xmit function of a virtual network card is as follows:

Static netdev_tx_t forward (struct sk_buff * SKB, struct net_device * Dev) {struct sdnat_struct * sdnat = netdev_priv (Dev); unsigned int flags = sdnat-> flags; struct nat_entry * entry; entry = find_sdnat_policy (SKB, flags); If (unlikely (! Entry) {goto xmit;} If (flags & SNAT) {do_trans_src (entry, SKB);} else if (flags & DNAT) {do_trans_dst (entry, SKB );} // at this time, skb dst imports data packets into the dst_entry of the NAT device. // to prevent cyclic routing, drop the data packets. Nat has been completed and skb_dst_drop (SKB) has not been used ); // clear the mark, because the packet is generally imported into the NAT device through the mark policy route // This is also to prevent the circular route SKB-> MARK = 0; xmit: netif_rx_ni (SKB); drop: kfree_skb (SKB); Return netdev_tx_ OK ;}


Do_trans_src/DST can be implemented using a function, which is used to make the interface clearer. The specific conversion is not much said. It is very simple. Modify the source address or target address of the IP header, and re-calculate the check code of L3 and L4.
The key is how to organize Nat rules. I use a nat_entry to save each rule:

Struct nat_entry {struct hlist_node hash_list; _ be32 key1; // For SNAT, that is, the original IP address, and DNAT, that is, the IP address to be converted to _ be32 key2; // For SNAT, that is, the IP address to be converted, for DNAT, that is, the original IP address _ be32 hash;/The jhash_2words value of the data packet source IP address or the target IP address int flags ;};


The hash calculation is as follows:

static u32 keys_get_hash(__be32 key){    return jhash_2words(key, 0x01, 0x0);}


When the module is loaded, two virtual NICS will be created, one responsible for SNAT, the other responsible for DNAT, and the system will also have two sdnat_struct structures, one responsible for SNAT and the other responsible for DNAT:

struct sdnat_struct {    int flags;    struct net_device   *dev;    struct hlist_head entrys[1024];};


In Linux, You need to configure two policy routes:
A. import data packets sent from the internal network port to the SNAT Nic device for Sant;
B. import data packets from the Internet port to the Intranet port to the DNAT Nic device for DNAT.
In this way, two-way automatic conversion is enabled. No matter from which the data is first initiated, the source address of the data packet from X is converted to y, convert the destination address of the data packet to "X ". Is it similar to Cisco static Nat? Define inbound and outbound devices instead of filtering data packets by iptables match. I prefer to use procfs as a user interface because it facilitates shell operations:
Echo + 192.168.1.1 9.24.100.1>/proc/NET/NAT
After the preceding command is executed, a nat_entry will be added to the hash table shared by the two NICs, key1 is 192.168.1.1, key2 is 9.24.100.1, and in the SNAT Nic device, the skb iph-> saddr will be used as the hash, and then the table will match its key1, And the key2 will be taken out as the IP address to be converted, in the DNAT Nic device, the skb iph-> daddr will be used as the hash, and then the table will match the key2, And the key1 will be taken out as the IP address to be converted. To delete a rule, run the following command:
Echo-192.168.1.1 9.24.100.1>/proc/NET/NAT
The rule routing rules are as follows:
IP rule add IIF $ Intranet port table SNAT
IP rule add IIF $ external port table DNAT
IP Route add 0.0.0.0/0 Dev snat0 table SNAT
IP Route add 0.0.0.0/0 Dev dnat0 table DNAT
Is it more efficient to determine whether to use NAT Based on routing? Instead of matching each packet through the netfilter module, you do not need to toss the inefficient ip_conntrack! It is worth noting that the xmit function of the sdnat device finally executes a netif_rx_ni, which is equivalent to re-injecting the data packet into itself. At this time, the IIF of the data packet will no longer be an intranet or Internet port, but it is a real sdant virtual network card device, so when the packet arrives at the routing module again, it will not enter the sdnat device again.

Thoughts and meanings

In addition to the netfilter framework, we can also use the Linux Nic device model to build another data packet filtering system. Yes, the idea is shown above. I have written several articles about how to save information in a route entry and obtain information by querying the route table. I used my own custom "route table ", the query method is still the longest prefix matching method, but the items saved in the route entry have changed. In this article, I show the idea of using a Linux native route table (not defined by myself) + a custom virtual Nic device to implement packet filtering. According to this idea, each target of iptables is a virtual network card device, and each series of matches is a route. The route entry of this route is to import data packets to the corresponding virtual network card device, the method of routing to match data packets will be more efficient than the netfilter method, because it uses an efficient data structure such as hash/trie, instead of traversing several layers of linked lists like netfilter.
In fact, is this idea quite new? No! Does the route entry have unreachable or blackhole? Aren't they exactly the reject and drop of iptables?


Implement a two-way Nat virtual network card

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.