Cisco and Linux nat-Linux implements Cisco-style Nat

Source: Internet
Author: User
Now that Cisco Nat is flexible, Can Linux implement it? The answer is yes! Linux netfilter is super flexible, and Linux Nat is not flexible because the iptables program is not flexible. xtables-Addons rawnat has taken an important step towards static Nat, iptables restricts the development of static Nat in Linux! So I put aside iptables, first implemented the kernel module based on Netfilter, and then used procfs as the user interface to see how to implement static Nat in the Cisco style. By the way, the reason for this program is that we have encountered this requirement in our products and all those who have used sip and FTP know it. However, due to the limited schedule, I am afraid that my work is unstable and the efficiency is not optimized. Therefore, I can only play with it here, so I will not go to the elegant hall.
First, let's take a look at the basic principle. We don't want a NAT to bind any n tuples or streams, but just a one-to-one address ing. Take the source address conversion as an example, in the direction from inside to outside, convert source address A to B, and in the direction from outside to inside, convert source target address B to! You must remember that at any time, the source address translation is done in postrouting, and the target address translation is done in prerouting. According to the above statement, the following description is provided:

With the instructions, we will know how to do it:
1. Maintain a ing table in the kernel and map only two addresses;
2. Perform Nat actions on the above ing table on the prerouting and postrouting hook points;
3. Implement a user interface to configure address ing from the user State

The preceding three points are easy to implement. In fact, static Nat can also be implemented using xtables-Addons rawnat. However, to achieve automatic matching of NAT in two directions, you must configure two or more entries, what hurts most is clearly a ing, which must be written in the form of match, so we should make it a Cisco style. In any case, the actual Nat part of the code below still uses the rawnat code!

The Code is as follows:

# Include <Linux/IP. h> # include <Linux/ipv6.h> # include <Linux/module. h> # include <Linux/skbuff. h> # include <Linux/TCP. h> # include <Linux/UDP. h> # include <Linux/list. h> # include <Linux/sysfs. h> # include <Linux/Fs. h> # include <Linux/proc_fs.h> # include <Linux/version. h> # include <Linux/netfilter. h> # include <net/IP. h> # include "compat_xtables.h" static inline _ be32remask (_ be32 ADDR, _ be32 repl, unsigned int Shi Ft) {uint32_t mask = (shift = 32 )? 0 :(~ (Uint32_t) 0> shift); Return htonl (ntohl (ADDR) & Mask) | (ntohl (repl )&~ Mask);} static void rawnat4_update_l4 (struct sk_buff * SKB, _ be32 oldip, _ be32 newip) {struct iphdr * IPH = ip_hdr (SKB ); void * transport_hdr = (void *) IPH + ip_hdrlen (SKB); struct tcphdr * tcph; struct udphdr * udph; bool cond; Switch (IPH-> protocol) {Case ipproto_tcp: tcph = transport_hdr; inet_proto_csum_replace4 (& tcph-> check, SKB, oldip, newip, true); break; Case ipproto_udp: Case ipproto_udplite: udph = tran Sport_hdr; cond = udph-> check! = 0; # If linux_version_code> = kernel_version (2, 6, 19) cond | = SKB-> ip_summed = checksum_partial; # endifif (Cond) {inet_proto_csum_replace4 (& udph-> check, SKB, oldip, newip, true); If (udph-> check = 0) udph-> check = csum_mangled_0;} break ;}} static unsigned int rawnat4_writable_part (const struct iphdr * iph) {unsigned int WLEN = sizeof (* iph); Switch (IPH-> protocol) {Case ipproto_tcp: WLEN + = sizeof (struct TC) Phdr); break; Case ipproto_udp: WLEN + = sizeof (struct udphdr); break;} return WLEN;} // implement source address conversion static unsigned intrawsnat (struct sk_buff ** pskb, _ be32 ADDR) {struct iphdr * IPH ;__ be32 new_addr; IPH = ip_hdr (* pskb); new_addr = remask (IPH-> saddr, ADDR, 32 ); if (IPH-> saddr = new_addr) {return nf_accept;} If (! Skb_make_writable (pskb, callback (IPH) {return nf_drop;} IPH = ip_hdr (* pskb); csum_replace4 (& IPH-> check, IPH-> saddr, new_addr ); translate (* pskb, IPH-> saddr, new_addr); IPH-> saddr = new_addr; return nf_accept;} // convert the target address to static unsigned intrawdnat (struct sk_buff ** pskb, _ be32 ADDR) {struct iphdr * IPH ;__ be32 new_addr; IPH = ip_hdr (* pskb); new_addr = remask (IPH-> daddr, ADDR, 32 ); if (IPH-> Daddr = new_addr) return nf_accept; If (! Skb_make_writable (pskb, rawnat4_writable_part (IPH) return nf_drop; IPH = ip_hdr (* pskb); csum_replace4 (& IPH-> check, IPH-> daddr, new_addr ); rawnat4_update_l4 (* pskb, IPH-> daddr, new_addr); IPH-> daddr = new_addr; return nf_accept;} // define the data structure struct addr_map {struct list_head list; __be32 ADDR [2]; int type; // 0: source address conversion; 1: target address conversion}; // Global Map liststatic list_head (map_list ); static unsigned int defaults 4_static_nat_pre (unsign Ed int hooknum, struct sk_buff * SKB, const struct net_device * In, const struct net_device * Out, INT (* okfn) (struct sk_buff *)) {__ be32 new_daddr = 0x0; struct addr_map * map; const struct iphdr * IPH = ip_hdr (SKB); If (list_empty (& map_list) {return nf_accept ;} // find whether the target address needs to be converted to list_for_each_entry (MAP, & map_list, list) {If (Map-> ADDR [(Map-> type-1) & amp; 0x00000001)] = IPH-> daddr) {new_daddr = map-> ADDR [Map-> ty PE & 0x00000001]; break; }}if (new_daddr = 0) {return nf_accept;} return rawdnat (& SKB, new_daddr );} static unsigned int ipv4_static_nat_post (unsigned int hooknum, struct sk_buff * SKB, const struct net_device * In, const struct net_device * Out, INT (* okfn) (struct sk_buff *)) {__ be32 new_saddr = 0x0; struct addr_map * map; const struct iphdr * IPH = ip_hdr (SKB); If (list_empty (& map_list) {return nf_accept ;} // query Find whether to convert the source address to list_for_each_entry (MAP, & map_list, list) {If (Map-> ADDR [Map-> type & 0x00000001] = IPH-> saddr) {new_saddr = map-> ADDR [(Map-> type-1) & 0x00000001)]; break ;}} if (new_saddr = 0) {return nf_accept ;} return rawsnat (& SKB, new_saddr);} static struct nf_hook_ops ipv4_static_nat [] _ read_mostly = {{. hook = ipv4_static_nat_pre ,. owner = this_module ,. pF = nfproto_ipv4 ,. hooknum = nf_inet_pre_routing,. Priority = nf_ip_pri_nat_src + 1 ,},{. hook = ipv4_static_nat_post ,. owner = this_module ,. pF = nfproto_ipv4 ,. hooknum = nf_inet_pre_routing ,. priority = nf_ip_pri_raw + 1 ,},}; // The following is a defined user interface // if you need to add a source conversion. Then:// Echo + 172.16.4.34-128.129.4.34>/proc/static_nat/sourceStruct proc_dir_entry * nat_entry = NULL; static ssize_t write_snat (struct file * file, const char _ User * Buf, size_t count, loff_t * PPOs) {struct addr_map * AM = NULL; char addr_temp [20] = {0 };__ be32 addr1 = 0, addr2 = 0; int ret = count; int I = 1; for (; I <48; I ++) {If (BUF [I] = '-') {memcpy (addr_temp, BUF + 1, I-1); break ;}} addr1 = in_aton (addr_temp ); addr2 = in_aton (BUF + I + 1); If (BUF [0] = '+') {Am = kzarloc (sizeof (struct addr_map), gfp_kernel ); init_list_head (& AM-> list); am-> ADDR [0] = addr1; am-> ADDR [1] = addr2; am-> type = 0; list_add (& AM-> list, & map_list);} else if (BUF [0] = '-') {// remove todo} return ret ;} static ssize_t write_dnat (struct file * file, const char _ User * Buf, size_t count, loff_t * PPOs) {// todoreturn 0;} static ssize_t read_snat (struct file * file, char _ User * Buf, size_t count, loff_t * PPOs) {// todoreturn 0;} static ssize_t read_dnat (struct file * file, char _ User * Buf, size_t count, loff_t * PPOs) {// todoreturn 0;} static const struct file_operations proc_snat_operations = {. read = read_snat ,. write = write_snat,}; static const struct file_operations proc_dnat_operations = {. read = read_dnat ,. write = write_dnat,}; static int _ init static_nat_zy_init (void) {int ret = 0; ret = forward (Listen 4_static_nat, array_size (Listen 4_static_nat); If (Ret <0) {printk ("Listen 4_static_nat: Can't register hooks. \ n ");}/* test */else {nat_entry = proc_mkdir (" static_nat ", null); proc_create (" Source ", s_iwusr, nat_entry, & proc_snat_operations ); proc_create ("destination", s_iwusr, nat_entry, & proc_dnat_operations);} return ret;} static void _ exit static_nat_zy_exit (void) {remove_proc_entry ("Source", nat_entry ); remove_proc_entry ("destination", nat_entry); remove_proc_entry ("static_nat", null); Round (ipv4_static_nat, array_size (ipv4_static_nat); return;} module_init ); module_exit (static_nat_zy_exit); // retain the original author module_author ("Jan engelhardt <jengelh@medozas.de>"); module_author ("wangran <marywangran@126.com>"); module_description ("static Nat "); module_license ("GPL ");

In this way, you can implement Cisoc-style Nat. There is still a lot of space for code optimization. For example, you can replace list with hash...

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.